aboutsummaryrefslogtreecommitdiff
path: root/dep
diff options
context:
space:
mode:
Diffstat (limited to 'dep')
-rw-r--r--dep/CMakeLists.txt29
-rw-r--r--dep/CascLib/CMakeLists.txt13
-rw-r--r--dep/PackageList.txt23
-rw-r--r--dep/SFMT/CMakeLists.txt15
-rw-r--r--dep/boost/CMakeLists.txt67
-rw-r--r--dep/bzip2/CMakeLists.txt33
-rw-r--r--dep/cppformat/CMakeLists.txt48
-rw-r--r--dep/cppformat/README.rst29
-rw-r--r--dep/cppformat/cppformat/format.cc (renamed from dep/cppformat/format.cc)118
-rw-r--r--dep/cppformat/cppformat/format.h (renamed from dep/cppformat/format.h)531
-rw-r--r--dep/cppformat/cppformat/posix.cc (renamed from dep/cppformat/posix.cc)4
-rw-r--r--dep/cppformat/cppformat/posix.h (renamed from dep/cppformat/posix.h)63
-rw-r--r--dep/efsw/.hg_archival.txt5
-rw-r--r--dep/efsw/CMakeLists.txt85
-rw-r--r--dep/efsw/LICENSE22
-rw-r--r--dep/efsw/README.md138
-rw-r--r--dep/efsw/include/efsw/efsw.h151
-rw-r--r--dep/efsw/include/efsw/efsw.hpp197
-rw-r--r--dep/efsw/src/efsw/Debug.cpp85
-rw-r--r--dep/efsw/src/efsw/Debug.hpp50
-rw-r--r--dep/efsw/src/efsw/DirWatcherGeneric.cpp451
-rw-r--r--dep/efsw/src/efsw/DirWatcherGeneric.hpp55
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshot.cpp261
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshot.hpp46
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshotDiff.cpp29
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshotDiff.hpp35
-rw-r--r--dep/efsw/src/efsw/FileInfo.cpp274
-rw-r--r--dep/efsw/src/efsw/FileInfo.hpp66
-rw-r--r--dep/efsw/src/efsw/FileSystem.cpp124
-rw-r--r--dep/efsw/src/efsw/FileSystem.hpp40
-rw-r--r--dep/efsw/src/efsw/FileWatcher.cpp145
-rw-r--r--dep/efsw/src/efsw/FileWatcherCWrapper.cpp132
-rw-r--r--dep/efsw/src/efsw/FileWatcherFSEvents.cpp278
-rw-r--r--dep/efsw/src/efsw/FileWatcherFSEvents.hpp107
-rw-r--r--dep/efsw/src/efsw/FileWatcherGeneric.cpp197
-rw-r--r--dep/efsw/src/efsw/FileWatcherGeneric.hpp59
-rw-r--r--dep/efsw/src/efsw/FileWatcherImpl.cpp29
-rw-r--r--dep/efsw/src/efsw/FileWatcherImpl.hpp54
-rw-r--r--dep/efsw/src/efsw/FileWatcherInotify.cpp531
-rw-r--r--dep/efsw/src/efsw/FileWatcherInotify.hpp73
-rw-r--r--dep/efsw/src/efsw/FileWatcherKqueue.cpp274
-rw-r--r--dep/efsw/src/efsw/FileWatcherKqueue.hpp78
-rw-r--r--dep/efsw/src/efsw/FileWatcherWin32.cpp291
-rw-r--r--dep/efsw/src/efsw/FileWatcherWin32.hpp69
-rw-r--r--dep/efsw/src/efsw/Log.cpp27
-rw-r--r--dep/efsw/src/efsw/Mutex.cpp26
-rw-r--r--dep/efsw/src/efsw/Mutex.hpp28
-rw-r--r--dep/efsw/src/efsw/String.cpp813
-rw-r--r--dep/efsw/src/efsw/String.hpp629
-rw-r--r--dep/efsw/src/efsw/System.cpp26
-rw-r--r--dep/efsw/src/efsw/System.hpp26
-rw-r--r--dep/efsw/src/efsw/Thread.cpp51
-rw-r--r--dep/efsw/src/efsw/Thread.hpp111
-rw-r--r--dep/efsw/src/efsw/Utf.hpp748
-rw-r--r--dep/efsw/src/efsw/Utf.inl671
-rw-r--r--dep/efsw/src/efsw/Watcher.cpp21
-rw-r--r--dep/efsw/src/efsw/Watcher.hpp30
-rw-r--r--dep/efsw/src/efsw/WatcherFSEvents.cpp264
-rw-r--r--dep/efsw/src/efsw/WatcherFSEvents.hpp70
-rw-r--r--dep/efsw/src/efsw/WatcherGeneric.cpp40
-rw-r--r--dep/efsw/src/efsw/WatcherGeneric.hpp30
-rw-r--r--dep/efsw/src/efsw/WatcherInotify.cpp35
-rw-r--r--dep/efsw/src/efsw/WatcherInotify.hpp25
-rw-r--r--dep/efsw/src/efsw/WatcherKqueue.cpp667
-rw-r--r--dep/efsw/src/efsw/WatcherKqueue.hpp94
-rw-r--r--dep/efsw/src/efsw/WatcherWin32.cpp150
-rw-r--r--dep/efsw/src/efsw/WatcherWin32.hpp77
-rw-r--r--dep/efsw/src/efsw/base.hpp110
-rw-r--r--dep/efsw/src/efsw/inotify-nosys.h159
-rw-r--r--dep/efsw/src/efsw/platform/platformimpl.hpp20
-rw-r--r--dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp144
-rw-r--r--dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp27
-rw-r--r--dep/efsw/src/efsw/platform/posix/MutexImpl.cpp32
-rw-r--r--dep/efsw/src/efsw/platform/posix/MutexImpl.hpp31
-rw-r--r--dep/efsw/src/efsw/platform/posix/SystemImpl.cpp180
-rw-r--r--dep/efsw/src/efsw/platform/posix/SystemImpl.hpp26
-rw-r--r--dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp68
-rw-r--r--dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp35
-rw-r--r--dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp89
-rw-r--r--dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp28
-rw-r--r--dep/efsw/src/efsw/platform/win/MutexImpl.cpp29
-rw-r--r--dep/efsw/src/efsw/platform/win/MutexImpl.hpp34
-rw-r--r--dep/efsw/src/efsw/platform/win/SystemImpl.cpp50
-rw-r--r--dep/efsw/src/efsw/platform/win/SystemImpl.hpp26
-rw-r--r--dep/efsw/src/efsw/platform/win/ThreadImpl.cpp56
-rw-r--r--dep/efsw/src/efsw/platform/win/ThreadImpl.hpp39
-rw-r--r--dep/efsw/src/efsw/sophist.h147
-rw-r--r--dep/efsw/src/test/efsw-test.cpp151
-rw-r--r--dep/g3dlite/CMakeLists.txt27
-rw-r--r--dep/gsoap/CMakeLists.txt25
-rw-r--r--dep/jemalloc/CMakeLists.txt123
-rw-r--r--dep/mysql/CMakeLists.txt (renamed from dep/zmqpp/CMakeLists.txt)29
-rw-r--r--dep/openssl/CMakeLists.txt26
-rw-r--r--dep/process/CMakeLists.txt19
-rw-r--r--dep/rapidjson/CMakeLists.txt20
-rw-r--r--dep/rapidjson/rapidjson/allocators.h261
-rw-r--r--dep/rapidjson/rapidjson/document.h2014
-rw-r--r--dep/rapidjson/rapidjson/encodedstream.h261
-rw-r--r--dep/rapidjson/rapidjson/encodings.h625
-rw-r--r--dep/rapidjson/rapidjson/error/en.h65
-rw-r--r--dep/rapidjson/rapidjson/error/error.h146
-rw-r--r--dep/rapidjson/rapidjson/filereadstream.h88
-rw-r--r--dep/rapidjson/rapidjson/filewritestream.h91
-rw-r--r--dep/rapidjson/rapidjson/internal/biginteger.h280
-rw-r--r--dep/rapidjson/rapidjson/internal/diyfp.h247
-rw-r--r--dep/rapidjson/rapidjson/internal/dtoa.h217
-rw-r--r--dep/rapidjson/rapidjson/internal/ieee754.h77
-rw-r--r--dep/rapidjson/rapidjson/internal/itoa.h304
-rw-r--r--dep/rapidjson/rapidjson/internal/meta.h181
-rw-r--r--dep/rapidjson/rapidjson/internal/pow10.h55
-rw-r--r--dep/rapidjson/rapidjson/internal/stack.h179
-rw-r--r--dep/rapidjson/rapidjson/internal/strfunc.h39
-rw-r--r--dep/rapidjson/rapidjson/internal/strtod.h270
-rw-r--r--dep/rapidjson/rapidjson/memorybuffer.h70
-rw-r--r--dep/rapidjson/rapidjson/memorystream.h61
-rw-r--r--dep/rapidjson/rapidjson/msinttypes/inttypes.h316
-rw-r--r--dep/rapidjson/rapidjson/msinttypes/stdint.h300
-rw-r--r--dep/rapidjson/rapidjson/prettywriter.h207
-rw-r--r--dep/rapidjson/rapidjson/rapidjson.h654
-rw-r--r--dep/rapidjson/rapidjson/reader.h1452
-rw-r--r--dep/rapidjson/rapidjson/stringbuffer.h93
-rw-r--r--dep/rapidjson/rapidjson/writer.h395
-rw-r--r--dep/readline/CMakeLists.txt38
-rw-r--r--dep/recastnavigation/Detour/CMakeLists.txt20
-rw-r--r--dep/recastnavigation/Recast/CMakeLists.txt21
-rw-r--r--dep/threads/CMakeLists.txt16
-rw-r--r--dep/utf8cpp/CMakeLists.txt15
-rw-r--r--dep/valgrind/CMakeLists.txt15
-rw-r--r--dep/zlib/CMakeLists.txt55
-rw-r--r--dep/zmqpp/zmqpp/compatibility.hpp97
-rw-r--r--dep/zmqpp/zmqpp/context.cpp54
-rw-r--r--dep/zmqpp/zmqpp/context.hpp184
-rw-r--r--dep/zmqpp/zmqpp/context_options.hpp26
-rw-r--r--dep/zmqpp/zmqpp/exception.hpp87
-rw-r--r--dep/zmqpp/zmqpp/frame.cpp95
-rw-r--r--dep/zmqpp/zmqpp/frame.hpp58
-rw-r--r--dep/zmqpp/zmqpp/inet.hpp175
-rw-r--r--dep/zmqpp/zmqpp/message.cpp454
-rw-r--r--dep/zmqpp/zmqpp/message.hpp254
-rw-r--r--dep/zmqpp/zmqpp/poller.cpp182
-rw-r--r--dep/zmqpp/zmqpp/poller.hpp186
-rw-r--r--dep/zmqpp/zmqpp/socket.cpp762
-rw-r--r--dep/zmqpp/zmqpp/socket.hpp500
-rw-r--r--dep/zmqpp/zmqpp/socket_options.hpp80
-rw-r--r--dep/zmqpp/zmqpp/socket_types.hpp148
-rw-r--r--dep/zmqpp/zmqpp/zmqpp.cpp30
-rw-r--r--dep/zmqpp/zmqpp/zmqpp.hpp111
-rw-r--r--dep/zmqpp/zmqpp_hotfix1.diff106
148 files changed, 20470 insertions, 4060 deletions
diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt
index 6caa1e1e70c..acbef0ca106 100644
--- a/dep/CMakeLists.txt
+++ b/dep/CMakeLists.txt
@@ -14,32 +14,31 @@ else()
add_definitions(-w)
endif()
-if(CMAKE_SYSTEM_NAME MATCHES "Linux")
- if(SERVERS AND NOT NOJEM)
- add_subdirectory(jemalloc)
- endif()
-endif()
-
-if(CMAKE_SYSTEM_NAME MATCHES "Windows")
- if(TOOLS)
- add_subdirectory(bzip2)
- endif()
- if(SERVERS OR TOOLS)
- add_subdirectory(zlib)
- endif()
-endif()
+add_subdirectory(threads)
if(SERVERS OR TOOLS)
+ add_subdirectory(boost)
+ add_subdirectory(zlib)
add_subdirectory(g3dlite)
add_subdirectory(recastnavigation)
+ add_subdirectory(jemalloc)
add_subdirectory(cppformat)
+ add_subdirectory(SFMT)
+ add_subdirectory(utf8cpp)
+ add_subdirectory(valgrind)
+ add_subdirectory(openssl)
endif()
if(SERVERS)
+ add_subdirectory(mysql)
+ add_subdirectory(process)
+ add_subdirectory(readline)
add_subdirectory(gsoap)
- add_subdirectory(zmqpp)
+ add_subdirectory(rapidjson)
+ add_subdirectory(efsw)
endif()
if(TOOLS)
+ add_subdirectory(bzip2)
add_subdirectory(CascLib)
endif()
diff --git a/dep/CascLib/CMakeLists.txt b/dep/CascLib/CMakeLists.txt
index 83b7ea38493..79be0a0830c 100644
--- a/dep/CascLib/CMakeLists.txt
+++ b/dep/CascLib/CMakeLists.txt
@@ -44,6 +44,15 @@ set(TOMCRYPT_FILES
src/libtomcrypt/src/misc/crypt_libc.c
)
-include_directories(${CMAKE_SOURCE_DIR}/dep)
-
add_library(casc STATIC ${SRC_FILES} ${TOMCRYPT_FILES})
+
+target_include_directories(casc
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ PRIVATE
+ ${CMAKE_SOURCE_DIR}/dep)
+
+set_target_properties(casc
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/PackageList.txt b/dep/PackageList.txt
index 5ad9cef5982..1e45d515902 100644
--- a/dep/PackageList.txt
+++ b/dep/PackageList.txt
@@ -1,6 +1,6 @@
TrinityCore uses (parts of or in whole) the following opensource software :
-Boost
+Boost (external)
http://www.boost.org
Version: 1.55
@@ -14,7 +14,11 @@ bzip2 (a freely available, patent free, high-quality data compressor)
cppformat (type safe format library)
https://github.com/cppformat/cppformat
- Version: 5c76d107cbaf5e851bd66b6c563e4fc7c90be7ad
+ Version: 5174b8ca281426af604b85fdf53be8a748b33f56
+
+efws (Entropia File System Watcher - crossplatform file system watcher)
+ https://bitbucket.org/SpartanJ/efsw
+ ff0b69daeca1edf7785a8a580518e462be5a6f3d
G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License)
http://g3d.sourceforge.net/
@@ -24,6 +28,14 @@ jemalloc (a general-purpose scalable concurrent malloc-implementation)
http://www.canonware.com/jemalloc/
Version: 3.6.0
+libreadline (command line editing library)
+ https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
+ Version: external
+
+OpenSSL (general-purpose cryptography library)
+ https://www.openssl.org/
+ Version: external
+
SFMT (SIMD-oriented Fast Mersenne Twister)
Based on http://agner.org/random/
Version: 2010-Aug-03
@@ -48,7 +60,6 @@ CascLib (An open-source implementation of library for reading CASC storage from
https://github.com/ladislav-zezula/CascLib
Version: 919a2d670cb749c501ee15887a88e9b9a538961b
-zmqpp (C++ binding for 0mq/zmq is a 'high-level' library that hides most of the c-style interface core 0mq provides.)
- https://github.com/zeromq/zmqpp
- Version: 3.2.0 17e9f6afa98f56ecac1e3f3eecbfc112357a6732
-
+rapidjson (A fast JSON parser/generator for C++ with both SAX/DOM style API http://rapidjson.org/)
+ https://github.com/miloyip/rapidjson
+ Version: v1.0.2
diff --git a/dep/SFMT/CMakeLists.txt b/dep/SFMT/CMakeLists.txt
new file mode 100644
index 00000000000..5cf1b9bf972
--- /dev/null
+++ b/dep/SFMT/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+add_library(sfmt INTERFACE)
+
+target_include_directories(sfmt
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/dep/boost/CMakeLists.txt b/dep/boost/CMakeLists.txt
new file mode 100644
index 00000000000..118635c85bd
--- /dev/null
+++ b/dep/boost/CMakeLists.txt
@@ -0,0 +1,67 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+if(WIN32)
+ set(BOOST_DEBUG ON)
+ if(DEFINED ENV{BOOST_ROOT})
+ set(BOOST_ROOT $ENV{BOOST_ROOT})
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0)
+ set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-12.0)
+ else()
+ set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.0)
+ endif()
+ else()
+ message(FATAL_ERROR "No BOOST_ROOT environment variable could be found! Please make sure it is set and the points to your Boost installation.")
+ endif()
+
+ set(Boost_USE_STATIC_LIBS ON)
+ set(Boost_USE_MULTITHREADED ON)
+ set(Boost_USE_STATIC_RUNTIME OFF)
+endif()
+
+find_package(Boost 1.51 REQUIRED system filesystem thread program_options iostreams regex)
+
+# Find if Boost was compiled in C++03 mode because it requires -DBOOST_NO_CXX11_SCOPED_ENUMS
+
+include (CheckCXXSourceCompiles)
+
+set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIR})
+set(CMAKE_REQUIRED_LIBRARIES ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_IOSTREAMS_LIBRARY})
+set(CMAKE_REQUIRED_FLAGS "-std=c++11")
+unset(boost_filesystem_copy_links_without_NO_SCOPED_ENUM CACHE)
+check_cxx_source_compiles("
+ #include <boost/filesystem/path.hpp>
+ #include <boost/filesystem/operations.hpp>
+ int main() { boost::filesystem::copy_file(boost::filesystem::path(), boost::filesystem::path()); }"
+boost_filesystem_copy_links_without_NO_SCOPED_ENUM)
+unset(CMAKE_REQUIRED_INCLUDES CACHE)
+unset(CMAKE_REQUIRED_LIBRARIES CACHE)
+unset(CMAKE_REQUIRED_FLAGS CACHE)
+
+if (NOT boost_filesystem_copy_links_without_NO_SCOPED_ENUM)
+ set(OPTIONAL_BOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS)
+endif()
+
+add_library(boost INTERFACE)
+
+target_link_libraries(boost
+ INTERFACE
+ ${Boost_LIBRARIES})
+
+target_include_directories(boost
+ INTERFACE
+ ${Boost_INCLUDE_DIRS})
+
+target_compile_definitions(boost
+ INTERFACE
+ -DBOOST_DATE_TIME_NO_LIB
+ -DBOOST_REGEX_NO_LIB
+ -DBOOST_CHRONO_NO_LIB
+ ${OPTIONAL_BOOST_NO_SCOPED_ENUMS})
diff --git a/dep/bzip2/CMakeLists.txt b/dep/bzip2/CMakeLists.txt
index d3aadbe002e..d5a7414f383 100644
--- a/dep/bzip2/CMakeLists.txt
+++ b/dep/bzip2/CMakeLists.txt
@@ -8,15 +8,30 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-file(GLOB sources *.c)
+if(UNIX)
+ # Look for an installed bzip2 on unix
+ find_package(BZip2 REQUIRED)
-set(bzip2_STAT_SRCS
- ${sources}
-)
+ add_library(bzip2 SHARED IMPORTED GLOBAL)
-include_directories(
- ${CMAKE_SOURCE_DIR}/dep/zlib
- ${CMAKE_CURRENT_SOURCE_DIR}
-)
+ set_target_properties(bzip2
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${BZIP2_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${BZIP2_INCLUDE_DIRS}")
+else()
+ # Use the bundled source on windows
+ file(GLOB sources *.c)
+ add_library(bzip2 STATIC
+ ${sources})
-add_library(bzip2 STATIC ${bzip2_STAT_SRCS})
+ target_include_directories(bzip2
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+ set_target_properties(bzip2
+ PROPERTIES
+ FOLDER
+ "dep")
+endif()
diff --git a/dep/cppformat/CMakeLists.txt b/dep/cppformat/CMakeLists.txt
index 3be3e5f6dbb..1cbff49b871 100644
--- a/dep/cppformat/CMakeLists.txt
+++ b/dep/cppformat/CMakeLists.txt
@@ -1,31 +1,37 @@
-include(CheckCXXCompilerFlag)
-include(CheckSymbolExists)
-
-set(FMT_SOURCES format.cc format.h)
-
-# Use variadic templates
-add_definitions(-DFMT_VARIADIC_TEMPLATES=1)
-
-# Use deleted functions
-add_definitions(-DFMT_USE_DELETED_FUNCTIONS=1)
-
-# Use static assert
-add_definitions(-DFMT_USE_STATIC_ASSERT=1)
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+include(CheckSymbolExists)
if (WIN32)
check_symbol_exists(open io.h HAVE_OPEN)
else ()
check_symbol_exists(open fcntl.h HAVE_OPEN)
endif ()
+set(FMT_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.cc)
+
if (HAVE_OPEN)
- add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1)
- set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h)
-endif ()
+ set(FMT_SOURCES ${FMT_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.cc)
+endif()
-add_library(format STATIC ${FMT_SOURCES})
+add_library(cppformat STATIC ${FMT_SOURCES})
-if (CMAKE_COMPILER_IS_GNUCXX)
- set_target_properties(format PROPERTIES COMPILE_FLAGS
- "-Wall -Wextra -Wshadow -pedantic")
-endif ()
+target_include_directories(cppformat
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+set_target_properties(cppformat
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/cppformat/README.rst b/dep/cppformat/README.rst
index fb4399f0af4..e859f909466 100644
--- a/dep/cppformat/README.rst
+++ b/dep/cppformat/README.rst
@@ -28,9 +28,9 @@ Features
* Format API with `format string syntax
<http://cppformat.github.io/latest/syntax.html>`_
similar to the one used by `str.format
- <http://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
+ <https://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
* Safe `printf implementation
- <http://cppformat.github.io/latest/reference.html#printf-formatting-functions>`_
+ <http://cppformat.github.io/latest/api.html#printf-formatting-functions>`_
including the POSIX extension for positional arguments.
* Support for user-defined types.
* High speed: performance of the format API is close to that of
@@ -103,10 +103,10 @@ An object of any user-defined type for which there is an overloaded
// s == "The date is 2012-12-9"
You can use the `FMT_VARIADIC
-<http://cppformat.github.io/latest/reference.html#utilities>`_
+<http://cppformat.github.io/latest/api.html#utilities>`_
macro to create your own functions similar to `format
-<http://cppformat.github.io/latest/reference.html#format>`_ and
-`print <http://cppformat.github.io/latest/reference.html#print>`_
+<http://cppformat.github.io/latest/api.html#format>`_ and
+`print <http://cppformat.github.io/latest/api.html#print>`_
which take arbitrary arguments:
.. code:: c++
@@ -132,13 +132,17 @@ Projects using this library
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
-* `HarpyWar/pvpgn <https://github.com/HarpyWar/pvpgn>`_:
+* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
-* `KBEngine <http://www.kbengine.org/>`_: An open-source MMOG server engine
+* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
+
+* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
+* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets
+
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
@@ -148,7 +152,7 @@ Projects using this library
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster proxy
-* `Saddy <https://code.google.com/p/saddy/>`_:
+* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
Small crossplatform 2D graphic engine
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
@@ -188,7 +192,7 @@ doesn't support user-defined types. Printf also has safety issues although
they are mostly solved with `__attribute__ ((format (printf, ...))
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
There is a POSIX extension that adds positional arguments required for
-`i18n <http://en.wikipedia.org/wiki/Internationalization_and_localization>`_
+`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
to printf but it is not a part of C99 and may not be available on some
platforms.
@@ -376,18 +380,13 @@ C++ Format is distributed under the BSD `license
The `Format String Syntax
<http://cppformat.github.io/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
-documentation <http://docs.python.org/3/library/string.html#module-string>`_
+documentation <https://docs.python.org/3/library/string.html#module-string>`_
adapted for the current library. For this reason the documentation is
distributed under the Python Software Foundation license available in
`doc/python-license.txt
<https://raw.github.com/cppformat/cppformat/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of C++ Format.
-Links
------
-
-`API changes/compatibility report <http://upstream-tracker.org/versions/cppformat.html>`_
-
Acknowledgments
---------------
diff --git a/dep/cppformat/format.cc b/dep/cppformat/cppformat/format.cc
index 1970d53c500..daccd68f1da 100644
--- a/dep/cppformat/format.cc
+++ b/dep/cppformat/cppformat/format.cc
@@ -207,10 +207,15 @@ void format_error_code(fmt::Writer &out, int error_code,
out.clear();
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
- fmt::internal::IntTraits<int>::MainType ec_value = error_code;
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
- error_code_size += fmt::internal::count_digits(ec_value);
+ typedef fmt::internal::IntTraits<int>::MainType MainType;
+ MainType abs_value = static_cast<MainType>(error_code);
+ if (internal::is_negative(error_code)) {
+ abs_value = 0 - abs_value;
+ ++error_code_size;
+ }
+ error_code_size += fmt::internal::count_digits(abs_value);
if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERROR_STR << error_code;
@@ -252,7 +257,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
template <typename T>
unsigned visit_any_int(T value) {
typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
- UnsignedType width = value;
+ UnsignedType width = static_cast<UnsignedType>(value);
if (fmt::internal::is_negative(value)) {
spec_.align_ = fmt::ALIGN_LEFT;
width = 0 - width;
@@ -278,8 +283,21 @@ class PrecisionHandler :
}
};
-// Converts an integer argument to an integral type T for printf.
+template <typename T, typename U>
+struct is_same {
+ enum { value = 0 };
+};
+
template <typename T>
+struct is_same<T, T> {
+ enum { value = 1 };
+};
+
+// An argument visitor that converts an integer argument to T for printf,
+// if T is an integral type. If T is void, the argument is converted to
+// corresponding signed or unsigned type depending on the type specifier:
+// 'd' and 'i' - signed, other - unsigned)
+template <typename T = void>
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
private:
fmt::internal::Arg &arg_;
@@ -300,21 +318,25 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
void visit_any_int(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
using fmt::internal::Arg;
- if (sizeof(T) <= sizeof(int)) {
+ typedef typename fmt::internal::Conditional<
+ is_same<T, void>::value, U, T>::type TargetType;
+ if (sizeof(TargetType) <= sizeof(int)) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_.type = Arg::INT;
- arg_.int_value = static_cast<int>(static_cast<T>(value));
+ arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
} else {
arg_.type = Arg::UINT;
- arg_.uint_value = static_cast<unsigned>(
- static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
+ typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned;
+ arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
}
} else {
if (is_signed) {
arg_.type = Arg::LONG_LONG;
- arg_.long_long_value =
- static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
+ // glibc's printf doesn't sign extend arguments of smaller types:
+ // std::printf("%lld", -42); // prints "4294967254"
+ // but we don't have to do the same because it's a UB.
+ arg_.long_long_value = static_cast<fmt::LongLong>(value);
} else {
arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value =
@@ -340,6 +362,21 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
arg_.int_value = static_cast<char>(value);
}
};
+
+// Write the content of w to os.
+void write(std::ostream &os, fmt::Writer &w) {
+ const char *data = w.data();
+ typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
+ UnsignedStreamSize size = w.size();
+ UnsignedStreamSize max_size =
+ internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
+ do {
+ UnsignedStreamSize n = size <= max_size ? size : max_size;
+ os.write(data, static_cast<std::streamsize>(n));
+ data += n;
+ size -= n;
+ } while (size != 0);
+}
} // namespace
namespace internal {
@@ -551,27 +588,25 @@ FMT_FUNC void fmt::WindowsError::init(
FMT_FUNC void fmt::internal::format_windows_error(
fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT {
- class String {
- private:
- LPWSTR str_;
-
- public:
- String() : str_() {}
- ~String() { LocalFree(str_); }
- LPWSTR *ptr() { return &str_; }
- LPCWSTR c_str() const { return str_; }
- };
FMT_TRY {
- String system_message;
- if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
- error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
- UTF16ToUTF8 utf8_message;
- if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
- out << message << ": " << utf8_message;
- return;
+ MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
+ buffer.resize(INLINE_BUFFER_SIZE);
+ for (;;) {
+ wchar_t *system_message = &buffer[0];
+ int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ system_message, static_cast<uint32_t>(buffer.size()), 0);
+ if (result != 0) {
+ UTF16ToUTF8 utf8_message;
+ if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
+ out << message << ": " << utf8_message;
+ return;
+ }
+ break;
}
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ break; // Can't get error message, report error code instead.
+ buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
@@ -616,7 +651,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
- map_.insert(Pair(named_arg->name, *named_arg));
+ map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
@@ -628,7 +663,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
- map_.insert(Pair(named_arg->name, *named_arg));
+ map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
@@ -637,7 +672,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
- map_.insert(Pair(named_arg->name, *named_arg));
+ map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
@@ -659,6 +694,7 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
break;
case Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
+ break;
default:
/*nothing*/;
}
@@ -763,7 +799,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
if (*s == '.') {
++s;
if ('0' <= *s && *s <= '9') {
- spec.precision_ = parse_nonnegative_int(s);
+ spec.precision_ = static_cast<int>(parse_nonnegative_int(s));
} else if (*s == '*') {
++s;
spec.precision_ = PrecisionHandler().visit(get_arg(s));
@@ -772,7 +808,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
Arg arg = get_arg(s, arg_index);
if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
- spec.flags_ &= ~HASH_FLAG;
+ spec.flags_ &= ~to_unsigned<int>(HASH_FLAG);
if (spec.fill_ == '0') {
if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC;
@@ -809,7 +845,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
break;
default:
--s;
- ArgConverter<int>(arg, *s).visit(arg);
+ ArgConverter<void>(arg, *s).visit(arg);
}
// Parse type.
@@ -861,10 +897,11 @@ FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
print(stdout, format_str, args);
}
-FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
+FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str,
+ ArgList args) {
MemoryWriter w;
w.write(format_str, args);
- os.write(w.data(), w.size());
+ write(os, w);
}
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
@@ -882,6 +919,13 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
}
+FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) {
+ MemoryWriter w;
+ printf(w, format, args);
+ write(os, w);
+ return static_cast<int>(w.size());
+}
+
#ifndef FMT_HEADER_ONLY
template struct fmt::internal::BasicData<void>;
diff --git a/dep/cppformat/format.h b/dep/cppformat/cppformat/format.h
index a98a166091b..08bb9b5d9e8 100644
--- a/dep/cppformat/format.h
+++ b/dep/cppformat/cppformat/format.h
@@ -28,14 +28,6 @@
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
-#if defined _MSC_VER && _MSC_VER <= 1500
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-typedef long long intmax_t;
-#else
-#include <stdint.h>
-#endif
-
#include <cassert>
#include <cmath>
#include <cstdio>
@@ -44,7 +36,8 @@ typedef long long intmax_t;
#include <memory>
#include <stdexcept>
#include <string>
-#include <map>
+#include <vector>
+#include <utility>
#ifndef FMT_USE_IOSTREAMS
# define FMT_USE_IOSTREAMS 1
@@ -64,40 +57,23 @@ typedef long long intmax_t;
# include <iterator>
#endif
-#ifdef _MSC_VER
-# include <intrin.h> // _BitScanReverse, _BitScanReverse64
-
-namespace fmt {
-namespace internal {
-# pragma intrinsic(_BitScanReverse)
-inline uint32_t clz(uint32_t x) {
- unsigned long r = 0;
- _BitScanReverse(&r, x);
- return 31 - r;
-}
-# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
-
-# ifdef _WIN64
-# pragma intrinsic(_BitScanReverse64)
-# endif
-
-inline uint32_t clzll(uint64_t x) {
- unsigned long r = 0;
-# ifdef _WIN64
- _BitScanReverse64(&r, x);
-# else
- // Scan the high 32 bits.
- if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
- return 63 - (r + 32);
+#if defined(_MSC_VER) && _MSC_VER <= 1500
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 intmax_t;
+#else
+#include <stdint.h>
+#endif
- // Scan the low 32 bits.
- _BitScanReverse(&r, static_cast<uint32_t>(x));
+#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
+# ifdef FMT_EXPORT
+# define FMT_API __declspec(dllexport)
+# elif defined(FMT_SHARED)
+# define FMT_API __declspec(dllimport)
# endif
- return 63 - r;
-}
-# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
-}
-}
+#endif
+#ifndef FMT_API
+# define FMT_API
#endif
#ifdef __GNUC__
@@ -174,21 +150,6 @@ inline uint32_t clzll(uint64_t x) {
# include <utility> // for std::move
#endif
-// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
-#ifndef FMT_USE_NOEXCEPT
-# define FMT_USE_NOEXCEPT 0
-#endif
-
-#ifndef FMT_NOEXCEPT
-# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
- (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
- _MSC_VER >= 1900
-# define FMT_NOEXCEPT noexcept
-# else
-# define FMT_NOEXCEPT throw()
-# endif
-#endif
-
// Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0
@@ -208,6 +169,25 @@ inline uint32_t clzll(uint64_t x) {
# endif
#endif
+// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
+#ifndef FMT_USE_NOEXCEPT
+# define FMT_USE_NOEXCEPT 0
+#endif
+
+#ifndef FMT_NOEXCEPT
+# if FMT_EXCEPTIONS
+# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
+ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
+ _MSC_VER >= 1900
+# define FMT_NOEXCEPT noexcept
+# else
+# define FMT_NOEXCEPT throw()
+# endif
+# else
+# define FMT_NOEXCEPT
+# endif
+#endif
+
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#ifndef FMT_USE_DELETED_FUNCTIONS
@@ -241,6 +221,67 @@ inline uint32_t clzll(uint64_t x) {
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
+
+#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
+# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
+#endif
+
+#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
+# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
+#endif
+
+// Some compilers masquerade as both MSVC and GCC-likes or
+// otherwise support __builtin_clz and __builtin_clzll, so
+// only define FMT_BUILTIN_CLZ using the MSVC intrinsics
+// if the clz and clzll builtins are not available.
+#if defined(_MSC_VER) && !defined(FMT_BUILTIN_CLZLL)
+# include <intrin.h> // _BitScanReverse, _BitScanReverse64
+
+namespace fmt {
+namespace internal {
+# pragma intrinsic(_BitScanReverse)
+inline uint32_t clz(uint32_t x) {
+ unsigned long r = 0;
+ _BitScanReverse(&r, x);
+
+ assert(x != 0);
+ // Static analysis complains about using uninitialized data
+ // "r", but the only way that can happen is if "x" is 0,
+ // which the callers guarantee to not happen.
+# pragma warning(suppress: 6102)
+ return 31 - r;
+}
+# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
+
+# ifdef _WIN64
+# pragma intrinsic(_BitScanReverse64)
+# endif
+
+inline uint32_t clzll(uint64_t x) {
+ unsigned long r = 0;
+# ifdef _WIN64
+ _BitScanReverse64(&r, x);
+# else
+ // Scan the high 32 bits.
+ if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
+ return 63 - (r + 32);
+
+ // Scan the low 32 bits.
+ _BitScanReverse(&r, static_cast<uint32_t>(x));
+# endif
+
+ assert(x != 0);
+ // Static analysis complains about using uninitialized data
+ // "r", but the only way that can happen is if "x" is 0,
+ // which the callers guarantee to not happen.
+# pragma warning(suppress: 6102)
+ return 63 - r;
+}
+# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
+}
+}
+#endif
+
namespace fmt {
namespace internal {
struct DummyInt {
@@ -396,7 +437,7 @@ class BasicStringRef {
return std::basic_string<Char>(data_, size_);
}
- /** Returns the pointer to a C string. */
+ /** Returns a pointer to the string data. */
const Char *data() const { return data_; }
/** Returns the string size. */
@@ -492,6 +533,29 @@ class FormatError : public std::runtime_error {
};
namespace internal {
+
+// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
+template <typename T>
+struct MakeUnsigned { typedef T Type; };
+
+#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
+ template <> \
+ struct MakeUnsigned<T> { typedef U Type; }
+
+FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char);
+FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char);
+FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short);
+FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned);
+FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long);
+FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong);
+
+// Casts nonnegative integer to unsigned.
+template <typename Int>
+inline typename MakeUnsigned<Int>::Type to_unsigned(Int value) {
+ FMT_ASSERT(value >= 0, "negative value");
+ return static_cast<typename MakeUnsigned<Int>::Type>(value);
+}
+
// The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation.
enum { INLINE_BUFFER_SIZE = 500 };
@@ -581,8 +645,7 @@ class Buffer {
template <typename T>
template <typename U>
void Buffer<T>::append(const U *begin, const U *end) {
- assert(begin <= end);
- std::size_t new_size = size_ + (end - begin);
+ std::size_t new_size = size_ + internal::to_unsigned(end - begin);
if (new_size > capacity_)
grow(new_size);
std::uninitialized_copy(begin, end,
@@ -592,8 +655,8 @@ void Buffer<T>::append(const U *begin, const U *end) {
namespace internal {
-// A memory buffer for POD types with the first SIZE elements stored in
-// the object itself.
+// A memory buffer for trivially copyable/constructible types with the first SIZE
+// elements stored in the object itself.
template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
class MemoryBuffer : private Allocator, public Buffer<T> {
private:
@@ -676,7 +739,7 @@ class FixedBuffer : public fmt::Buffer<Char> {
FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {}
protected:
- void grow(std::size_t size);
+ FMT_API void grow(std::size_t size);
};
template <typename Char>
@@ -704,7 +767,7 @@ class CharTraits<char> : public BasicCharTraits<char> {
// Formats a floating-point number.
template <typename T>
- static int format_float(char *buffer, std::size_t size,
+ FMT_API static int format_float(char *buffer, std::size_t size,
const char *format, unsigned width, int precision, T value);
};
@@ -715,7 +778,7 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
static wchar_t convert(wchar_t value) { return value; }
template <typename T>
- static int format_float(wchar_t *buffer, std::size_t size,
+ FMT_API static int format_float(wchar_t *buffer, std::size_t size,
const wchar_t *format, unsigned width, int precision, T value);
};
@@ -754,27 +817,12 @@ struct IntTraits {
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
};
-// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
-template <typename T>
-struct MakeUnsigned { typedef T Type; };
-
-#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
- template <> \
- struct MakeUnsigned<T> { typedef U Type; }
-
-FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char);
-FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char);
-FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short);
-FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned);
-FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long);
-FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong);
-
-void report_unknown_type(char code, const char *type);
+FMT_API void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only
// configuration.
template <typename T = void>
-struct BasicData {
+struct FMT_API BasicData {
static const uint32_t POWERS_OF_10_32[];
static const uint64_t POWERS_OF_10_64[];
static const char DIGITS[];
@@ -782,22 +830,14 @@ struct BasicData {
typedef BasicData<> Data;
-#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
-# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
-#endif
-
-#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
-# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
-#endif
-
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
inline unsigned count_digits(uint64_t n) {
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
- unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
- return t - (n < Data::POWERS_OF_10_64[t]) + 1;
+ int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
+ return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1;
}
#else
// Fallback version of count_digits used when __builtin_clz is not available.
@@ -820,8 +860,8 @@ inline unsigned count_digits(uint64_t n) {
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
inline unsigned count_digits(uint32_t n) {
- uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
- return t - (n < Data::POWERS_OF_10_32[t]) + 1;
+ int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
+ return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1;
}
#endif
@@ -863,7 +903,7 @@ class UTF8ToUTF16 {
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_;
public:
- explicit UTF8ToUTF16(StringRef s);
+ FMT_API explicit UTF8ToUTF16(StringRef s);
operator WStringRef() const { return WStringRef(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const wchar_t *c_str() const { return &buffer_[0]; }
@@ -878,7 +918,7 @@ class UTF16ToUTF8 {
public:
UTF16ToUTF8() {}
- explicit UTF16ToUTF8(WStringRef s);
+ FMT_API explicit UTF16ToUTF8(WStringRef s);
operator StringRef() const { return StringRef(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const char *c_str() const { return &buffer_[0]; }
@@ -887,15 +927,15 @@ class UTF16ToUTF8 {
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
// in case of memory allocation error.
- int convert(WStringRef s);
+ FMT_API int convert(WStringRef s);
};
-void format_windows_error(fmt::Writer &out, int error_code,
- fmt::StringRef message) FMT_NOEXCEPT;
+FMT_API void format_windows_error(fmt::Writer &out, int error_code,
+ fmt::StringRef message) FMT_NOEXCEPT;
#endif
-void format_system_error(fmt::Writer &out, int error_code,
- fmt::StringRef message) FMT_NOEXCEPT;
+FMT_API void format_system_error(fmt::Writer &out, int error_code,
+ fmt::StringRef message) FMT_NOEXCEPT;
// A formatting argument value.
struct Value {
@@ -938,8 +978,8 @@ struct Value {
};
};
-// A formatting argument. It is a POD type to allow storage in
-// internal::MemoryBuffer.
+// A formatting argument. It is a trivially copyable/constructible type to
+// allow storage in internal::MemoryBuffer.
struct Arg : Value {
Type type;
};
@@ -976,6 +1016,7 @@ template <typename T>
T &get();
struct DummyStream : std::ostream {
+ DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
void operator<<(Null<>);
};
@@ -1199,17 +1240,27 @@ class MakeValue : public Arg {
static uint64_t type(const NamedArg<Char_> &) { return Arg::NAMED_ARG; }
};
+template <typename Formatter>
+class MakeArg : public Arg {
+public:
+ MakeArg() {
+ type = Arg::NONE;
+ }
+
+ template <typename T>
+ MakeArg(const T &value)
+ : Arg(MakeValue<Formatter>(value)) {
+ type = static_cast<Arg::Type>(MakeValue<Formatter>::type(value));
+ }
+};
+
template <typename Char>
struct NamedArg : Arg {
BasicStringRef<Char> name;
- typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
-
template <typename T>
NamedArg(BasicStringRef<Char> argname, const T &value)
- : Arg(MakeValue(value)), name(argname) {
- type = static_cast<Arg::Type>(MakeValue::type(value));
- }
+ : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {}
};
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
@@ -1631,17 +1682,22 @@ namespace internal {
template <typename Char>
class ArgMap {
private:
- typedef std::map<fmt::BasicStringRef<Char>, internal::Arg> MapType;
+ typedef std::vector<std::pair<fmt::BasicStringRef<Char>, internal::Arg> > MapType;
typedef typename MapType::value_type Pair;
MapType map_;
public:
- void init(const ArgList &args);
+ FMT_API void init(const ArgList &args);
const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const {
- typename MapType::const_iterator it = map_.find(name);
- return it != map_.end() ? &it->second : 0;
+ // The list is unsorted, so just return the first matching name.
+ for (typename MapType::const_iterator it = map_.begin(), end = map_.end();
+ it != end; ++it) {
+ if (it->first == name)
+ return &it->second;
+ }
+ return 0;
}
};
@@ -1767,7 +1823,7 @@ class FormatterBase {
int next_arg_index_;
// Returns the argument with specified index.
- Arg do_get_arg(unsigned arg_index, const char *&error);
+ FMT_API Arg do_get_arg(unsigned arg_index, const char *&error);
protected:
const ArgList &args() const { return args_; }
@@ -1780,7 +1836,7 @@ class FormatterBase {
// Returns the next argument.
Arg next_arg(const char *&error) {
if (next_arg_index_ >= 0)
- return do_get_arg(next_arg_index_++, error);
+ return do_get_arg(internal::to_unsigned(next_arg_index_++), error);
error = "cannot switch from manual to automatic argument indexing";
return Arg();
}
@@ -1803,7 +1859,7 @@ class FormatterBase {
template <typename Char>
void write(BasicWriter<Char> &w, const Char *start, const Char *end) {
if (start != end)
- w << BasicStringRef<Char>(start, end - start);
+ w << BasicStringRef<Char>(start, internal::to_unsigned(end - start));
}
};
@@ -1823,14 +1879,16 @@ class PrintfFormatter : private FormatterBase {
public:
explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {}
- void format(BasicWriter<Char> &writer, BasicCStringRef<Char> format_str);
+ FMT_API void format(BasicWriter<Char> &writer,
+ BasicCStringRef<Char> format_str);
};
} // namespace internal
-// A formatter.
+/** This template formats data and writes the output to a writer. */
template <typename CharType>
class BasicFormatter : private internal::FormatterBase {
public:
+ /** The character type for the output. */
typedef CharType Char;
private:
@@ -1852,13 +1910,23 @@ class BasicFormatter : private internal::FormatterBase {
internal::Arg parse_arg_name(const Char *&s);
public:
+ /**
+ \rst
+ Constructs a ``BasicFormatter`` object. References to the arguments and
+ the writer are stored in the formatter object so make sure they have
+ appropriate lifetimes.
+ \endrst
+ */
BasicFormatter(const ArgList &args, BasicWriter<Char> &w)
: internal::FormatterBase(args), writer_(w) {}
+ /** Returns a reference to the writer associated with this formatter. */
BasicWriter<Char> &writer() { return writer_; }
+ /** Formats stored arguments and writes the output to the writer. */
void format(BasicCStringRef<Char> format_str);
+ // Formats a single argument and advances format_str, a format string pointer.
const Char *format(const Char *&format_str, const internal::Arg &arg);
};
@@ -1889,16 +1957,29 @@ inline uint64_t make_type(const T &arg) {
return MakeValue< BasicFormatter<char> >::type(arg);
}
+template <unsigned N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)>
+struct ArgArray;
+
+template <unsigned N>
+struct ArgArray<N, true/*IsPacked*/> {
+ typedef Value Type[N > 0 ? N : 1];
+
+ template <typename Formatter, typename T>
+ static Value make(const T &value) {
+ Value result = MakeValue<Formatter>(value);
+ // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang:
+ // https://github.com/cppformat/cppformat/issues/276
+ (void)result.custom.format;
+ return result;
+ }
+};
+
template <unsigned N>
-struct ArgArray {
- // Computes the argument array size by adding 1 to N, which is the number of
- // arguments, if N is zero, because array of zero size is invalid, or if N
- // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
- // argument that marks the end of the list.
- enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) };
-
- typedef typename Conditional<
- (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE];
+struct ArgArray<N, false/*IsPacked*/> {
+ typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE
+
+ template <typename Formatter, typename T>
+ static Arg make(const T &value) { return MakeArg<Formatter>(value); }
};
#if FMT_USE_VARIADIC_TEMPLATES
@@ -1907,47 +1988,6 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) {
return make_type(first) | (make_type(tail...) << 4);
}
-inline void do_set_types(Arg *) {}
-
-template <typename T, typename... Args>
-inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) {
- args->type = static_cast<Arg::Type>(
- MakeValue< BasicFormatter<char> >::type(arg));
- do_set_types(args + 1, tail...);
-}
-
-template <typename... Args>
-inline void set_types(Arg *array, const Args & ... args) {
- if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS))
- do_set_types(array, args...);
- array[sizeof...(Args)].type = Arg::NONE;
-}
-
-template <typename... Args>
-inline void set_types(Value *, const Args & ...) {
- // Do nothing as types are passed separately from values.
-}
-
-template <typename Formatter, typename Value>
-inline void store_args(Value *) {}
-
-template <typename Formatter, typename Arg, typename T, typename... Args>
-inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
- // Assign only the Value subobject of Arg and don't overwrite type (if any)
- // that is assigned by set_types.
- Value &value = *args;
- value = MakeValue<Formatter>(arg);
- store_args<Formatter>(args + 1, tail...);
-}
-
-template <typename Formatter, typename... Args>
-ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
- const Args & ... args) {
- if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS))
- set_types(array, args...);
- store_args<Formatter>(array, args...);
- return ArgList(make_type(args...), array);
-}
#else
struct ArgType {
@@ -1985,7 +2025,7 @@ class FormatBuf : public std::basic_streambuf<Char> {
int_type overflow(int_type ch = traits_type::eof()) {
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
- size_t size = this->pptr() - start_;
+ size_t size = this->size();
buffer_.resize(size);
buffer_.reserve(size * 2);
@@ -1997,7 +2037,7 @@ class FormatBuf : public std::basic_streambuf<Char> {
}
size_t size() const {
- return this->pptr() - start_;
+ return to_unsigned(this->pptr() - start_);
}
};
} // namespace internal
@@ -2015,18 +2055,20 @@ class FormatBuf : public std::basic_streambuf<Char> {
# define FMT_VARIADIC_VOID(func, arg_type) \
template <typename... Args> \
void func(arg_type arg0, const Args & ... args) { \
- typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
- func(arg0, fmt::internal::make_arg_list< \
- fmt::BasicFormatter<Char> >(array, args...)); \
+ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
+ typename ArgArray::Type array{ \
+ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
+ func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \
}
// Defines a variadic constructor.
# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
template <typename... Args> \
ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
- typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
- func(arg0, arg1, fmt::internal::make_arg_list< \
- fmt::BasicFormatter<Char> >(array, args...)); \
+ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
+ typename ArgArray::Type array{ \
+ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
+ func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \
}
#else
@@ -2207,7 +2249,8 @@ class BasicWriter {
// Writes a decimal integer.
template <typename Int>
void write_decimal(Int value) {
- typename internal::IntTraits<Int>::MainType abs_value = value;
+ typedef typename internal::IntTraits<Int>::MainType MainType;
+ MainType abs_value = static_cast<MainType>(value);
if (internal::is_negative(value)) {
abs_value = 0 - abs_value;
*write_unsigned_decimal(abs_value, 1) = '-';
@@ -2474,9 +2517,9 @@ void BasicWriter<Char>::write_str(
return;
}
}
- std::size_t precision = spec.precision_;
+ std::size_t precision = static_cast<std::size_t>(spec.precision_);
if (spec.precision_ >= 0 && precision < str_size)
- str_size = spec.precision_;
+ str_size = precision;
write_str(str_value, str_size, spec);
}
@@ -2510,7 +2553,8 @@ typename BasicWriter<Char>::CharPtr
// is specified.
if (prefix_size > 0 && prefix[prefix_size - 1] == '0')
--prefix_size;
- unsigned number_size = prefix_size + spec.precision();
+ unsigned number_size =
+ prefix_size + internal::to_unsigned(spec.precision());
AlignSpec subspec(number_size, '0', ALIGN_NUMERIC);
if (number_size >= width)
return prepare_int_buffer(num_digits, subspec, prefix, prefix_size);
@@ -2564,7 +2608,7 @@ template <typename T, typename Spec>
void BasicWriter<Char>::write_int(T value, Spec spec) {
unsigned prefix_size = 0;
typedef typename internal::IntTraits<T>::MainType UnsignedType;
- UnsignedType abs_value = value;
+ UnsignedType abs_value = static_cast<UnsignedType>(value);
char prefix[4] = "";
if (internal::is_negative(value)) {
prefix[0] = '-';
@@ -2643,8 +2687,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
template <typename Char>
template <typename T>
-void BasicWriter<Char>::write_double(
- T value, const FormatSpec &spec) {
+void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) {
// Check type.
char type = spec.type();
bool upper = false;
@@ -2744,6 +2787,8 @@ void BasicWriter<Char>::write_double(
// Format using snprintf.
Char fill = internal::CharTraits<Char>::cast(spec.fill());
+ unsigned n = 0;
+ Char *start = 0;
for (;;) {
std::size_t buffer_size = buffer_.capacity() - offset;
#ifdef _MSC_VER
@@ -2755,41 +2800,44 @@ void BasicWriter<Char>::write_double(
buffer_size = buffer_.capacity() - offset;
}
#endif
- Char *start = &buffer_[offset];
- int n = internal::CharTraits<Char>::format_float(
+ start = &buffer_[offset];
+ int result = internal::CharTraits<Char>::format_float(
start, buffer_size, format, width_for_sprintf, spec.precision(), value);
- if (n >= 0 && offset + n < buffer_.capacity()) {
- if (sign) {
- if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
- *start != ' ') {
- *(start - 1) = sign;
- sign = 0;
- } else {
- *(start - 1) = fill;
- }
- ++n;
- }
- if (spec.align() == ALIGN_CENTER &&
- spec.width() > static_cast<unsigned>(n)) {
- width = spec.width();
- CharPtr p = grow_buffer(width);
- std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char));
- fill_padding(p, spec.width(), n, fill);
- return;
- }
- if (spec.fill() != ' ' || sign) {
- while (*start == ' ')
- *start++ = fill;
- if (sign)
- *(start - 1) = sign;
- }
- grow_buffer(n);
- return;
+ if (result >= 0) {
+ n = internal::to_unsigned(result);
+ if (offset + n < buffer_.capacity())
+ break; // The buffer is large enough - continue with formatting.
+ buffer_.reserve(offset + n + 1);
+ } else {
+ // If result is negative we ask to increase the capacity by at least 1,
+ // but as std::vector, the buffer grows exponentially.
+ buffer_.reserve(buffer_.capacity() + 1);
}
- // If n is negative we ask to increase the capacity by at least 1,
- // but as std::vector, the buffer grows exponentially.
- buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
}
+ if (sign) {
+ if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
+ *start != ' ') {
+ *(start - 1) = sign;
+ sign = 0;
+ } else {
+ *(start - 1) = fill;
+ }
+ ++n;
+ }
+ if (spec.align() == ALIGN_CENTER && spec.width() > n) {
+ width = spec.width();
+ CharPtr p = grow_buffer(width);
+ std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char));
+ fill_padding(p, spec.width(), n, fill);
+ return;
+ }
+ if (spec.fill() != ' ' || sign) {
+ while (*start == ' ')
+ *start++ = fill;
+ if (sign)
+ *(start - 1) = sign;
+ }
+ grow_buffer(n);
}
/**
@@ -2920,22 +2968,21 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
output << value;
BasicStringRef<Char> str(&buffer[0], format_buf.size());
- typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
- internal::Arg arg = MakeValue(str);
- arg.type = static_cast<internal::Arg::Type>(MakeValue::type(str));
- format_str = f.format(format_str, arg);
+ typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
+ format_str = f.format(format_str, MakeArg(str));
}
// Reports a system error without throwing an exception.
// Can be used to report errors from destructors.
-void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
+FMT_API void report_system_error(int error_code,
+ StringRef message) FMT_NOEXCEPT;
#if FMT_USE_WINDOWS_H
/** A Windows error. */
class WindowsError : public SystemError {
private:
- void init(int error_code, CStringRef format_str, ArgList args);
+ FMT_API void init(int error_code, CStringRef format_str, ArgList args);
public:
/**
@@ -2974,7 +3021,8 @@ class WindowsError : public SystemError {
// Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors.
-void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;
+FMT_API void report_windows_error(int error_code,
+ StringRef message) FMT_NOEXCEPT;
#endif
@@ -2986,7 +3034,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
Example:
print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23);
*/
-void print_colored(Color c, CStringRef format, ArgList args);
+FMT_API void print_colored(Color c, CStringRef format, ArgList args);
/**
\rst
@@ -3018,7 +3066,7 @@ inline std::wstring format(WCStringRef format_str, ArgList args) {
print(stderr, "Don't {}!", "panic");
\endrst
*/
-void print(std::FILE *f, CStringRef format_str, ArgList args);
+FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args);
/**
\rst
@@ -3029,7 +3077,7 @@ void print(std::FILE *f, CStringRef format_str, ArgList args);
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
-void print(CStringRef format_str, ArgList args);
+FMT_API void print(CStringRef format_str, ArgList args);
template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
@@ -3066,7 +3114,7 @@ inline std::wstring sprintf(WCStringRef format, ArgList args) {
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
-int fprintf(std::FILE *f, CStringRef format, ArgList args);
+FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
/**
\rst
@@ -3132,10 +3180,10 @@ class FormatInt {
explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {}
explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {}
- /**
- Returns the number of characters written to the output buffer.
- */
- std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; }
+ /** Returns the number of characters written to the output buffer. */
+ std::size_t size() const {
+ return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1);
+ }
/**
Returns a pointer to the output buffer content. No terminating null
@@ -3165,7 +3213,8 @@ class FormatInt {
// write a terminating null character.
template <typename T>
inline void format_decimal(char *&buffer, T value) {
- typename internal::IntTraits<T>::MainType abs_value = value;
+ typedef typename internal::IntTraits<T>::MainType MainType;
+ MainType abs_value = static_cast<MainType>(value);
if (internal::is_negative(value)) {
*buffer++ = '-';
abs_value = 0 - abs_value;
@@ -3245,10 +3294,11 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
template <typename... Args> \
ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const Args & ... args) { \
- typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
+ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
+ typename ArgArray::Type array{ \
+ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
- fmt::internal::make_arg_list< \
- fmt::BasicFormatter<Char> >(array, args...)); \
+ fmt::ArgList(fmt::internal::make_type(args...), array)); \
}
#else
// Defines a wrapper for a function taking __VA_ARGS__ arguments
@@ -3361,8 +3411,20 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
print(cerr, "Don't {}!", "panic");
\endrst
*/
-void print(std::ostream &os, CStringRef format_str, ArgList args);
+FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
+
+/**
+ \rst
+ Prints formatted data to the stream *os*.
+
+ **Example**::
+
+ fprintf(cerr, "Don't %s!", "panic");
+ \endrst
+ */
+FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
+FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
#endif
namespace internal {
@@ -3374,7 +3436,7 @@ inline bool is_name_start(Char c) {
// Parses an unsigned integer advancing s to the end of the parsed input.
// This function assumes that the first character of s is a digit.
template <typename Char>
-int parse_nonnegative_int(const Char *&s) {
+unsigned parse_nonnegative_int(const Char *&s) {
assert('0' <= *s && *s <= '9');
unsigned value = 0;
do {
@@ -3453,7 +3515,6 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) {
return arg;
}
-// Should be after FormatSpec
template <typename Char>
const Char *BasicFormatter<Char>::format(
const Char *&format_str, const internal::Arg &arg) {
diff --git a/dep/cppformat/posix.cc b/dep/cppformat/cppformat/posix.cc
index 756281a0ebd..c6c2ae2c413 100644
--- a/dep/cppformat/posix.cc
+++ b/dep/cppformat/cppformat/posix.cc
@@ -173,7 +173,7 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) {
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot read from file");
- return result;
+ return internal::to_unsigned(result);
}
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
@@ -181,7 +181,7 @@ std::size_t fmt::File::write(const void *buffer, std::size_t count) {
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot write to file");
- return result;
+ return internal::to_unsigned(result);
}
fmt::File fmt::File::dup(int fd) {
diff --git a/dep/cppformat/posix.h b/dep/cppformat/cppformat/posix.h
index 88bcb4f557b..bfbd3851838 100644
--- a/dep/cppformat/posix.h
+++ b/dep/cppformat/cppformat/posix.h
@@ -34,11 +34,17 @@
#endif
#include <errno.h>
-#include <fcntl.h> // for O_RDONLY
+#include <fcntl.h> // for O_RDONLY
+#include <locale.h> // for locale_t
#include <stdio.h>
+#include <stdlib.h> // for strtod_l
#include <cstddef>
+#ifdef __APPLE__
+# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
+#endif
+
#include "format.h"
#ifndef FMT_POSIX
@@ -299,7 +305,8 @@ class File {
// Closes the file.
void close();
- // Returns the file size.
+ // Returns the file size. The size has signed type for consistency with
+ // stat::st_size.
LongLong size() const;
// Attempts to read count bytes from the file into the specified buffer.
@@ -331,6 +338,58 @@ class File {
// Returns the memory page size.
long getpagesize();
+
+#if defined(LC_NUMERIC_MASK) || defined(_MSC_VER)
+# define FMT_LOCALE
+#endif
+
+#ifdef FMT_LOCALE
+// A "C" numeric locale.
+class Locale {
+ private:
+# ifdef _MSC_VER
+ typedef _locale_t locale_t;
+
+ enum { LC_NUMERIC_MASK = LC_NUMERIC };
+
+ static locale_t newlocale(int category_mask, const char *locale, locale_t) {
+ return _create_locale(category_mask, locale);
+ }
+
+ static void freelocale(locale_t locale) {
+ _free_locale(locale);
+ }
+
+ static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
+ return _strtod_l(nptr, endptr, locale);
+ }
+# endif
+
+ locale_t locale_;
+
+ FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
+
+ public:
+ typedef locale_t Type;
+
+ Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) {
+ if (!locale_)
+ throw fmt::SystemError(errno, "cannot create locale");
+ }
+ ~Locale() { freelocale(locale_); }
+
+ Type get() const { return locale_; }
+
+ // Converts string to floating-point number and advances str past the end
+ // of the parsed input.
+ double strtod(const char *&str) const {
+ char *end = 0;
+ double result = strtod_l(str, &end, locale_);
+ str = end;
+ return result;
+ }
+};
+#endif // FMT_LOCALE
} // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES
diff --git a/dep/efsw/.hg_archival.txt b/dep/efsw/.hg_archival.txt
new file mode 100644
index 00000000000..19565afb668
--- /dev/null
+++ b/dep/efsw/.hg_archival.txt
@@ -0,0 +1,5 @@
+repo: 78c2ea8c48b213ee0078d6326a1dd719d0844764
+node: ff0b69daeca1edf7785a8a580518e462be5a6f3d
+branch: default
+latesttag: null
+latesttagdistance: 144
diff --git a/dep/efsw/CMakeLists.txt b/dep/efsw/CMakeLists.txt
new file mode 100644
index 00000000000..81a1d20b204
--- /dev/null
+++ b/dep/efsw/CMakeLists.txt
@@ -0,0 +1,85 @@
+if (WITH_DYNAMIC_LINKING)
+ set(SRCS
+ src/efsw/DirectorySnapshot.cpp
+ src/efsw/DirectorySnapshotDiff.cpp
+ src/efsw/DirWatcherGeneric.cpp
+ src/efsw/FileInfo.cpp
+ src/efsw/FileSystem.cpp
+ src/efsw/FileWatcher.cpp
+ src/efsw/FileWatcherCWrapper.cpp
+ src/efsw/FileWatcherGeneric.cpp
+ src/efsw/FileWatcherImpl.cpp
+ src/efsw/Log.cpp
+ src/efsw/Mutex.cpp
+ src/efsw/String.cpp
+ src/efsw/System.cpp
+ src/efsw/Thread.cpp
+ src/efsw/Watcher.cpp
+ src/efsw/WatcherGeneric.cpp)
+
+ if(WIN32)
+ list(APPEND SRCS
+ src/efsw/platform/win/FileSystemImpl.cpp
+ src/efsw/platform/win/MutexImpl.cpp
+ src/efsw/platform/win/SystemImpl.cpp
+ src/efsw/platform/win/ThreadImpl.cpp)
+ else()
+ list(APPEND SRCS
+ src/efsw/platform/posix/FileSystemImpl.cpp
+ src/efsw/platform/posix/MutexImpl.cpp
+ src/efsw/platform/posix/SystemImpl.cpp
+ src/efsw/platform/posix/ThreadImpl.cpp)
+ endif()
+
+ if (WIN32)
+ list(APPEND SRCS
+ src/efsw/WatcherWin32.cpp
+ src/efsw/FileWatcherWin32.cpp)
+ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ list(APPEND SRCS
+ src/efsw/FileWatcherInotify.cpp
+ src/efsw/WatcherInotify.cpp)
+
+ if (NOT EXISTS "/usr/include/sys/inotify.h" AND NOT EXISTS "/usr/local/include/sys/inotify.h")
+ add_definitions(-DEFSW_INOTIFY_NOSYS)
+ endif()
+ elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR APPLE)
+ list(APPEND SRCS
+ src/efsw/FileWatcherKqueue.cpp
+ src/efsw/WatcherKqueue.cpp)
+
+ if (APPLE)
+ list(APPEND SRCS
+ src/efsw/FileWatcherFSEvents.cpp
+ src/efsw/WatcherFSEvents.cpp)
+
+ exec_program(uname ARGS -v OUTPUT_VARIABLE OSX_VERSION)
+ string(REGEX MATCH "[0-9]+" OSX_VERSION ${OSX_VERSION})
+ if (NOT OSX_VERSION GREATER 9)
+ add_definitions(-DEFSW_FSEVENTS_NOT_SUPPORTED)
+ endif()
+
+ set(OPTIONAL_MAC_LINK_LIBRARIES "-framework CoreFoundation" "-framework CoreServices")
+ endif()
+ endif()
+
+ add_library(efsw STATIC ${SRCS})
+
+ target_include_directories(efsw
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src)
+
+ target_link_libraries(efsw
+ PUBLIC
+ threads
+ ${OPTIONAL_MAC_LINK_LIBRARIES})
+
+ set_target_properties(efsw
+ PROPERTIES
+ FOLDER
+ "dep")
+else()
+ add_library(efsw INTERFACE)
+endif()
diff --git a/dep/efsw/LICENSE b/dep/efsw/LICENSE
new file mode 100644
index 00000000000..ac8ac28988d
--- /dev/null
+++ b/dep/efsw/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Martín Lucas Golini
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
+http://code.google.com/p/simplefilewatcher/ also MIT licensed. \ No newline at end of file
diff --git a/dep/efsw/README.md b/dep/efsw/README.md
new file mode 100644
index 00000000000..fda0bb599aa
--- /dev/null
+++ b/dep/efsw/README.md
@@ -0,0 +1,138 @@
+Entropia File System Watcher
+============================
+**efsw** is a C++ cross-platform file system watcher and notifier.
+
+**efsw** monitors the file system asynchronously for changes to files and directories by watching a list of specified paths, and raises events when a directory or file change.
+
+**efsw** supports recursive directories watch, tracking the entire sub directory tree.
+
+**efsw** currently supports the following platforms:
+
+* Linux via [inotify](http://en.wikipedia.org/wiki/Inotify)
+
+* Windows via [I/O Completion Ports](http://en.wikipedia.org/wiki/IOCP)
+
+* Mac OS X via [FSEvents](http://en.wikipedia.org/wiki/FSEvents) or [kqueue](http://en.wikipedia.org/wiki/Kqueue)
+
+* FreeBSD/BSD via [kqueue](http://en.wikipedia.org/wiki/Kqueue)
+
+* OS-independent generic watcher
+(polling the disk for directory snapshots and comparing them periodically)
+
+If any of the backend fails to start by any reason, it will fallback to the OS-independent implementation.
+This should never happen, except for the Kqueue implementation, see `Platform limitations and clarifications`.
+
+**Code License**
+--------------
+[MIT License](http://www.opensource.org/licenses/mit-license.php)
+
+**Some example code:**
+--------------------
+
+ :::c++
+ // Inherits from the abstract listener class, and implements the the file action handler
+ class UpdateListener : public efsw::FileWatchListener
+ {
+ public:
+ UpdateListener() {}
+
+ void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" )
+ {
+ switch( action )
+ {
+ case efsw::Actions::Add:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Added" << std::endl;
+ break;
+ case efsw::Actions::Delete:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Delete" << std::endl;
+ break;
+ case efsw::Actions::Modified:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Modified" << std::endl;
+ break;
+ case efsw::Actions::Moved:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Moved from (" << oldFilename << ")" << std::endl;
+ break;
+ default:
+ std::cout << "Should never happen!" << std::endl;
+ }
+ }
+ };
+
+ // Create the file system watcher instance
+ // efsw::FileWatcher allow a first boolean parameter that indicates if it should start with the generic file watcher instead of the platform specific backend
+ efsw::FileWatcher * fileWatcher = new efsw::FileWatcher();
+
+ // Create the instance of your efsw::FileWatcherListener implementation
+ UpdateListener * listener = new UpdateListener();
+
+ // Add a folder to watch, and get the efsw::WatchID
+ // It will watch the /tmp folder recursively ( the third parameter indicates that is recursive )
+ // Reporting the files and directories changes to the instance of the listener
+ efsw::WatchID watchID = fileWatcher->addWatch( "/tmp", listener, true );
+
+ // Adds another directory to watch. This time as non-recursive.
+ efsw::WatchID watchID2 = fileWatcher->addWatch( "/usr", listener, false );
+
+ // Start watching asynchronously the directories
+ fileWatcher.watch();
+
+ // Remove the second watcher added
+ // You can also call removeWatch by passing the watch path ( it must end with an slash or backslash in windows, since that's how internally it's saved )
+ fileWatcher->removeWatch( watchID2 );
+
+**Dependencies**
+--------------
+None :)
+
+**Compiling**
+------------
+To generate project files you will need to [download and install](http://industriousone.com/premake/download) [Premake](http://industriousone.com/what-premake)
+
+Then you can generate the project for your platform just going to the project directory where the premake4.lua file is located and then execute:
+
+`premake4 gmake` to generate project Makefiles, then `cd make/*YOURPLATFORM*/`, and finally `make` or `make config=release` ( it will generate the static lib, the shared lib and the test application ).
+
+or
+
+`premake4 vs2010` to generate Visual Studio 2010 project.
+
+or
+
+`premake4 xcode4` to generate Xcode 4 project.
+
+There is also a cmake file that i don't oficially support but it works just fine, provided by [Mohammed Nafees](https://bitbucket.org/binaryking).
+
+**Platform limitations and clarifications**
+-------------------------------------------
+
+Directory paths are expected to be encoded as UTF-8 strings in all platforms.
+
+handleFileAction returns UTF-8 strings in all platforms.
+
+Windows and FSEvents Mac OS X implementation can't follow symlinks ( it will ignore followSymlinks() and allowOutOfScopeLinks() ).
+
+Kqueue implementation is limited by the maximun number of file descriptors allowed per process by the OS, in the case of reaching the file descriptors limit ( in BSD around 18000 and in OS X around 10240 ) it will fallback to the generic file watcher.
+
+OS X will only use Kqueue if OS X version is below to 10.5, and this implementation needs to be compiled separately from the OS X >= 10.5 implementation. Since there's no way to compile FSEvents backend in OS X below 10.5.
+
+FSEvents for OS X Lion and beyond in some cases will generate more actions that in reality ocurred, since fine-grained implementation of FSEvents doesn't give the order of the actions retrieved, in some cases i need to guess/aproximate the order of them.
+
+Generic watcher relies on the inode information to detect file and directories renames/move. Since Windows has no concept of inodes as Unix platforms do, there is no current reliable way of determining file/directory movement on Windows without help from the Windows API ( this is replaced with Add/Delete events ).
+
+Linux versions below 2.6.13 are not supported, since inotify wasn't implemented yet. I'm not interested in support older kernels, since i don't see the point. If someone needs this open an issue in the issue tracker and i may consider implenent a dnotify backend.
+
+OS-independent watcher, Kqueue and FSEvents for OS X below 10.5 keep cache of the directories structures, to be able to detect changes in the directories. This means that there's a memory overhead for this backends.
+
+**Useful information**
+--------------------
+The project also comes with a C API wrapper, contributed by [Sepul Sepehr Taghdisian](https://bitbucket.org/sepul).
+
+There's a string manipulation class not exposed in the efsw header ( efsw::String ) that can be used to make string encoding conversion.
+
+
+**Clarifications**
+----------------
+
+This software started as a fork of the [simplefilewatcher](http://code.google.com/p/simplefilewatcher/) by James Wynn (james[at]jameswynn.com), [MIT licensed](http://www.opensource.org/licenses/mit-license.html).
+
+The icon used for the project is part of the [Haiku®'s Icons](http://www.haiku-inc.org/haiku-icons.html), [MIT licensed](http://www.opensource.org/licenses/mit-license.html).
diff --git a/dep/efsw/include/efsw/efsw.h b/dep/efsw/include/efsw/efsw.h
new file mode 100644
index 00000000000..28e63e2139e
--- /dev/null
+++ b/dep/efsw/include/efsw/efsw.h
@@ -0,0 +1,151 @@
+/**
+ @author Sepul Sepehr Taghdisian
+
+ Copyright (c) 2013 Martin Lucas Golini
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
+ http://code.google.com/p/simplefilewatcher/ also MIT licensed.
+*/
+/** This is the C API wrapper of EFSW */
+#ifndef ESFW_H
+#define ESFW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_WIN32)
+ #ifdef EFSW_DYNAMIC
+ // Windows platforms
+ #ifdef EFSW_EXPORTS
+ // From DLL side, we must export
+ #define EFSW_API __declspec(dllexport)
+ #else
+ // From client application side, we must import
+ #define EFSW_API __declspec(dllimport)
+ #endif
+ #else
+ // No specific directive needed for static build
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+ #endif
+#else
+ #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS )
+ #define EFSW_API __attribute__ ((visibility("default")))
+ #endif
+
+ // Other platforms don't need to define anything
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+#endif
+
+/// Type for a watch id
+typedef long efsw_watchid;
+
+/// Type for watcher
+typedef void* efsw_watcher;
+
+enum efsw_action
+{
+ EFSW_ADD = 1, /// Sent when a file is created or renamed
+ EFSW_DELETE = 2, /// Sent when a file is deleted or renamed
+ EFSW_MODIFIED = 3, /// Sent when a file is modified
+ EFSW_MOVED = 4 /// Sent when a file is moved
+};
+
+enum efsw_error
+{
+ EFSW_NOTFOUND = -1,
+ EFSW_REPEATED = -2,
+ EFSW_OUTOFSCOPE = -3,
+ EFSW_NOTREADABLE = -4,
+ EFSW_REMOTE = -5,
+ EFSW_UNSPECIFIED = -6
+};
+
+/// Basic interface for listening for file events.
+typedef void (*efsw_pfn_fileaction_callback) (
+ efsw_watcher watcher,
+ efsw_watchid watchid,
+ const char* dir,
+ const char* filename,
+ enum efsw_action action,
+ const char* old_filename,
+ void* param
+);
+
+/**
+ * Creates a new file-watcher
+ * @param generic_mode Force the use of the Generic file watcher
+ */
+efsw_watcher EFSW_API efsw_create(int generic_mode);
+
+/// Release the file-watcher and unwatch any directories
+void EFSW_API efsw_release(efsw_watcher watcher);
+
+/// Retreive last error occured by file-watcher
+EFSW_API const char* efsw_getlasterror();
+
+/// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
+/// For backwards compatibility.
+/// On error returns WatchID with Error type.
+efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory,
+ efsw_pfn_fileaction_callback callback_fn, int recursive, void* param);
+
+/// Remove a directory watch. This is a brute force search O(nlogn).
+void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory);
+
+/// Remove a directory watch. This is a map lookup O(logn).
+void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid);
+
+/// Starts watching ( in other thread )
+void EFSW_API efsw_watch(efsw_watcher watcher);
+
+/**
+ * Allow recursive watchers to follow symbolic links to other directories
+ * followSymlinks is disabled by default
+ */
+void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable);
+
+/** @return If can follow symbolic links to directorioes */
+int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher);
+
+/**
+ * When enable this it will allow symlinks to watch recursively out of the pointed directory.
+ * follorSymlinks must be enabled to this work.
+ * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed,
+ * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion.
+ * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ).
+ * Buy enabling out of scope links, it will allow this behavior.
+ * allowOutOfScopeLinks are disabled by default.
+ */
+void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow);
+
+/// @return Returns if out of scope links are allowed
+int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dep/efsw/include/efsw/efsw.hpp b/dep/efsw/include/efsw/efsw.hpp
new file mode 100644
index 00000000000..0693bb296f0
--- /dev/null
+++ b/dep/efsw/include/efsw/efsw.hpp
@@ -0,0 +1,197 @@
+/**
+ @author Martín Lucas Golini
+
+ Copyright (c) 2013 Martín Lucas Golini
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
+ http://code.google.com/p/simplefilewatcher/ also MIT licensed.
+*/
+
+#ifndef ESFW_HPP
+#define ESFW_HPP
+
+#include <string>
+#include <list>
+
+#if defined(_WIN32)
+ #ifdef EFSW_DYNAMIC
+ // Windows platforms
+ #ifdef EFSW_EXPORTS
+ // From DLL side, we must export
+ #define EFSW_API __declspec(dllexport)
+ #else
+ // From client application side, we must import
+ #define EFSW_API __declspec(dllimport)
+ #endif
+ #else
+ // No specific directive needed for static build
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+ #endif
+#else
+ #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS )
+ #define EFSW_API __attribute__ ((visibility("default")))
+ #endif
+
+ // Other platforms don't need to define anything
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+#endif
+
+namespace efsw {
+
+/// Type for a watch id
+typedef long WatchID;
+
+// forward declarations
+class FileWatcherImpl;
+class FileWatchListener;
+
+/// Actions to listen for. Rename will send two events, one for
+/// the deletion of the old file, and one for the creation of the
+/// new file.
+namespace Actions {
+ enum Action
+ {
+ /// Sent when a file is created or renamed
+ Add = 1,
+ /// Sent when a file is deleted or renamed
+ Delete = 2,
+ /// Sent when a file is modified
+ Modified = 3,
+ /// Sent when a file is moved
+ Moved = 4
+ };
+}
+typedef Actions::Action Action;
+
+/// Errors log namespace
+namespace Errors {
+
+enum Error
+{
+ FileNotFound = -1,
+ FileRepeated = -2,
+ FileOutOfScope = -3,
+ FileNotReadable = -4,
+ FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to watch this directory ). */
+ Unspecified = -6
+};
+
+class EFSW_API Log
+{
+ public:
+ /// @return The last error logged
+ static std::string getLastErrorLog();
+
+ /// Creates an error of the type specified
+ static Error createLastError( Error err, std::string log );
+};
+
+}
+typedef Errors::Error Error;
+
+/// Listens to files and directories and dispatches events
+/// to notify the listener of files and directories changes.
+/// @class FileWatcher
+class EFSW_API FileWatcher
+{
+ public:
+ /// Default constructor, will use the default platform file watcher
+ FileWatcher();
+
+ /// Constructor that lets you force the use of the Generic File Watcher
+ FileWatcher( bool useGenericFileWatcher );
+
+ virtual ~FileWatcher();
+
+ /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
+ /// For backwards compatibility.
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher);
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Starts watching ( in other thread )
+ void watch();
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+
+ /** Allow recursive watchers to follow symbolic links to other directories
+ * followSymlinks is disabled by default
+ */
+ void followSymlinks( bool follow );
+
+ /** @return If can follow symbolic links to directorioes */
+ const bool& followSymlinks() const;
+
+ /** When enable this it will allow symlinks to watch recursively out of the pointed directory.
+ * follorSymlinks must be enabled to this work.
+ * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed,
+ * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion.
+ * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ).
+ * Buy enabling out of scope links, it will allow this behavior.
+ * allowOutOfScopeLinks are disabled by default.
+ */
+ void allowOutOfScopeLinks( bool allow );
+
+ /// @return Returns if out of scope links are allowed
+ const bool& allowOutOfScopeLinks() const;
+ private:
+ /// The implementation
+ FileWatcherImpl * mImpl;
+ bool mFollowSymlinks;
+ bool mOutOfScopeLinks;
+};
+
+/// Basic interface for listening for file events.
+/// @class FileWatchListener
+class FileWatchListener
+{
+ public:
+ FileWatchListener() {}
+
+ virtual ~FileWatchListener() {}
+
+ /// Handles the action file action
+ /// @param watchid The watch id for the directory
+ /// @param dir The directory
+ /// @param filename The filename that was accessed (not full path)
+ /// @param action Action that was performed
+ /// @param oldFilename The name of the file or directory moved
+ virtual void handleFileAction(WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" ) = 0;
+
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/Debug.cpp b/dep/efsw/src/efsw/Debug.cpp
new file mode 100644
index 00000000000..9c4ee02e5b6
--- /dev/null
+++ b/dep/efsw/src/efsw/Debug.cpp
@@ -0,0 +1,85 @@
+#include <efsw/Debug.hpp>
+#include <iostream>
+
+#ifdef EFSW_COMPILER_MSVC
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <crtdbg.h>
+#endif
+
+#include <cassert>
+#include <cstdio>
+#include <cstdarg>
+
+namespace efsw {
+
+#ifdef DEBUG
+
+void efREPORT_ASSERT( const char * File, int Line, const char * Exp )
+{
+ #ifdef EFSW_COMPILER_MSVC
+ _CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp);
+
+ DebugBreak();
+ #else
+ std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl;
+
+ #if defined(EFSW_COMPILER_GCC) && defined(EFSW_32BIT) && !defined(EFSW_ARM)
+ asm("int3");
+ #else
+ assert( false );
+ #endif
+ #endif
+}
+
+void efPRINT( const char * format, ... )
+{
+ char buf[2048];
+ va_list args;
+
+ va_start( args, format );
+
+ #ifdef EFSW_COMPILER_MSVC
+ _vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0]), format, args );
+ #else
+ vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args );
+ #endif
+
+ va_end( args );
+
+ #ifdef EFSW_COMPILER_MSVC
+ OutputDebugStringA( buf );
+ #else
+ std::cout << buf;
+ #endif
+}
+
+void efPRINTC( unsigned int cond, const char * format, ...)
+{
+ if ( 0 == cond )
+ return;
+
+ char buf[2048];
+ va_list args;
+
+ va_start( args, format );
+
+ #ifdef EFSW_COMPILER_MSVC
+ _vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args );
+ #else
+ vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args );
+ #endif
+
+ va_end( args );
+
+ #ifdef EFSW_COMPILER_MSVC
+ OutputDebugStringA( buf );
+ #else
+ std::cout << buf;
+ #endif
+}
+
+#endif
+
+}
+
diff --git a/dep/efsw/src/efsw/Debug.hpp b/dep/efsw/src/efsw/Debug.hpp
new file mode 100644
index 00000000000..75d6dce0466
--- /dev/null
+++ b/dep/efsw/src/efsw/Debug.hpp
@@ -0,0 +1,50 @@
+#ifndef EFSW_DEBUG_HPP
+#define EFSW_DEBUG_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+#ifdef DEBUG
+
+void efREPORT_ASSERT( const char * File, const int Line, const char * Exp );
+
+#define efASSERT( expr ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #expr ); }
+#define efASSERTM( expr, msg ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #msg ); }
+
+void efPRINT ( const char * format, ... );
+void efPRINTC ( unsigned int cond, const char * format, ... );
+
+#else
+
+#define efASSERT( expr )
+#define efASSERTM( expr, msg )
+
+#ifndef EFSW_COMPILER_MSVC
+ #define efPRINT( format, args... ) {}
+ #define efPRINTC( cond, format, args... ) {}
+#else
+ #define efPRINT
+ #define efPRINTC
+#endif
+
+#endif
+
+#ifdef EFSW_VERBOSE
+ #define efDEBUG efPRINT
+ #define efDEBUGC efPRINTC
+#else
+
+ #ifndef EFSW_COMPILER_MSVC
+ #define efDEBUG( format, args... ) {}
+ #define efDEBUGC( cond, format, args... ) {}
+ #else
+ #define efDEBUG
+ #define efDEBUGC
+ #endif
+
+#endif
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/DirWatcherGeneric.cpp b/dep/efsw/src/efsw/DirWatcherGeneric.cpp
new file mode 100644
index 00000000000..b80c14d24ce
--- /dev/null
+++ b/dep/efsw/src/efsw/DirWatcherGeneric.cpp
@@ -0,0 +1,451 @@
+#include <efsw/DirWatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/Debug.hpp>
+#include <efsw/String.hpp>
+
+namespace efsw {
+
+DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles ) :
+ Parent( parent ),
+ Watch( ws ),
+ Recursive( recursive ),
+ Deleted( false )
+{
+ resetDirectory( directory );
+
+ if ( !reportNewFiles )
+ {
+ DirSnap.scan();
+ }
+ else
+ {
+ DirectorySnapshotDiff Diff = DirSnap.scan();
+
+ if ( Diff.changed() )
+ {
+ FileInfoList::iterator it;
+
+ DiffIterator( FilesCreated )
+ {
+ handleAction( ( *it ).Filepath, Actions::Add );
+ }
+ }
+ }
+}
+
+DirWatcherGeneric::~DirWatcherGeneric()
+{
+ /// If the directory was deleted mark the files as deleted
+ if ( Deleted )
+ {
+ DirectorySnapshotDiff Diff = DirSnap.scan();
+
+ if ( !DirSnap.exists() )
+ {
+ FileInfoList::iterator it;
+
+ DiffIterator( FilesDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ }
+
+ DiffIterator( DirsDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ }
+ }
+ }
+
+ DirWatchMap::iterator it = Directories.begin();
+
+ for ( ; it != Directories.end(); it++ )
+ {
+ if ( Deleted )
+ {
+ /// If the directory was deleted, mark the flag for file deletion
+ it->second->Deleted = true;
+ }
+
+ efSAFE_DELETE( it->second );
+ }
+}
+
+void DirWatcherGeneric::resetDirectory( std::string directory )
+{
+ std::string dir( directory );
+
+ /// Is this a recursive watch?
+ if ( Watch->Directory != directory )
+ {
+ if ( !( directory.size() && ( directory.at(0) == FileSystem::getOSSlash() || directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) )
+ {
+ /// Get the real directory
+ if ( NULL != Parent )
+ {
+ FileSystem::dirAddSlashAtEnd(directory);
+
+ dir = Parent->DirSnap.DirectoryInfo.Filepath + directory;
+ }
+ else
+ {
+ efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." );
+ }
+ }
+ }
+
+ DirSnap.setDirectoryInfo( dir );
+}
+
+void DirWatcherGeneric::handleAction( const std::string &filename, unsigned long action, std::string oldFilename)
+{
+ Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath, FileSystem::fileNameFromPath( filename ), (Action)action, oldFilename );
+}
+
+void DirWatcherGeneric::addChilds( bool reportNewFiles )
+{
+ if ( Recursive )
+ {
+ /// Create the subdirectories watchers
+ std::string dir;
+
+ for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ )
+ {
+ if ( it->second.isDirectory() && it->second.isReadable() && !FileSystem::isRemoteFS( it->second.Filepath ) )
+ {
+ /// Check if the directory is a symbolic link
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) );
+
+ dir = it->first;
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() )
+ {
+ continue;
+ }
+
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) )
+ {
+ continue;
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+ else
+ {
+ if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) )
+ {
+ continue;
+ }
+ }
+
+ if ( reportNewFiles )
+ {
+ handleAction( dir, Actions::Add );
+ }
+
+ Directories[dir] = new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles );
+
+ Directories[dir]->addChilds( reportNewFiles );
+ }
+ }
+ }
+}
+
+void DirWatcherGeneric::watch( bool reportOwnChange )
+{
+ DirectorySnapshotDiff Diff = DirSnap.scan();
+
+ if ( reportOwnChange && Diff.DirChanged && NULL != Parent )
+ {
+ Watch->Listener->handleFileAction( Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ), FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified );
+ }
+
+ if ( Diff.changed() )
+ {
+ FileInfoList::iterator it;
+ MovedList::iterator mit;
+
+ /// Files
+ DiffIterator( FilesCreated )
+ {
+ handleAction( (*it).Filepath, Actions::Add );
+ }
+
+ DiffIterator( FilesModified )
+ {
+ handleAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( FilesDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ }
+
+ DiffMovedIterator( FilesMoved )
+ {
+ handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
+ }
+
+ /// Directories
+ DiffIterator( DirsCreated )
+ {
+ createDirectory( (*it).Filepath );
+ }
+
+ DiffIterator( DirsModified )
+ {
+ handleAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( DirsDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ removeDirectory( (*it).Filepath );
+ }
+
+ DiffMovedIterator( DirsMoved )
+ {
+ handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
+ moveDirectory( (*mit).first, (*mit).second.Filepath );
+ }
+ }
+
+ /// Process the subdirectories looking for changes
+ for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); dit++ )
+ {
+ /// Just watch
+ dit->second->watch();
+ }
+}
+
+void DirWatcherGeneric::watchDir( std::string &dir )
+{
+ DirWatcherGeneric * watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks() ?
+ findDirWatcher( dir ) :
+ findDirWatcherFast( dir );
+
+ if ( NULL != watcher )
+ {
+ watcher->watch( true );
+ }
+}
+
+DirWatcherGeneric * DirWatcherGeneric::findDirWatcherFast( std::string dir )
+{
+ // remove the common base ( dir should always start with the same base as the watcher )
+ efASSERT( !dir.empty() );
+ efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() );
+ efASSERT( DirSnap.DirectoryInfo.Filepath == dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) );
+
+ if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() )
+ {
+ dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 );
+ }
+
+ if ( dir.size() == 1 )
+ {
+ efASSERT( dir[0] == FileSystem::getOSSlash() );
+ return this;
+ }
+
+ size_t level = 0;
+ std::vector<std::string> dirv = String::split( dir, FileSystem::getOSSlash(), false );
+
+ DirWatcherGeneric * watcher = this;
+
+ while ( level < dirv.size() )
+ {
+ // search the dir level in the current watcher
+ DirWatchMap::iterator it = watcher->Directories.find( dirv[ level ] );
+
+ // found? continue with the next level
+ if ( it != watcher->Directories.end() )
+ {
+ watcher = it->second;
+
+ level++;
+ }
+ else
+ {
+ // couldn't found the folder level?
+ // directory not watched
+ return NULL;
+ }
+ }
+
+ return watcher;
+}
+
+DirWatcherGeneric * DirWatcherGeneric::findDirWatcher( std::string dir )
+{
+ if ( DirSnap.DirectoryInfo.Filepath == dir )
+ {
+ return this;
+ }
+ else
+ {
+ DirWatcherGeneric * watcher = NULL;
+
+ for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ )
+ {
+ watcher = it->second->findDirWatcher( dir );
+
+ if ( NULL != watcher )
+ {
+ return watcher;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+DirWatcherGeneric * DirWatcherGeneric::createDirectory( std::string newdir )
+{
+ FileSystem::dirRemoveSlashAtEnd( newdir );
+ newdir = FileSystem::fileNameFromPath( newdir );
+
+ DirWatcherGeneric * dw = NULL;
+
+ /// Check if the directory is a symbolic link
+ std::string dir( DirSnap.DirectoryInfo.Filepath + newdir );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) )
+ {
+ return NULL;
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+ bool skip = false;
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() )
+ {
+ skip = true;
+ }
+
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) )
+ {
+ skip = true;
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+ else
+ {
+ if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) )
+ {
+ skip = true;
+ }
+ }
+
+ if ( !skip )
+ {
+ handleAction( newdir, Actions::Add );
+
+ /// Creates the new directory watcher of the subfolder and check for new files
+ dw = new DirWatcherGeneric( this, Watch, dir, Recursive );
+
+ dw->addChilds();
+
+ dw->watch();
+
+ /// Add it to the list of directories
+ Directories[ newdir ] = dw;
+ }
+
+ return dw;
+}
+
+void DirWatcherGeneric::removeDirectory( std::string dir )
+{
+ FileSystem::dirRemoveSlashAtEnd( dir );
+ dir = FileSystem::fileNameFromPath( dir );
+
+ DirWatcherGeneric * dw = NULL;
+ DirWatchMap::iterator dit;
+
+ /// Folder deleted
+
+ /// Search the folder, it should exists
+ dit = Directories.find( dir );
+
+ if ( dit != Directories.end() )
+ {
+ dw = dit->second;
+
+ /// Flag it as deleted so it fire the event for every file inside deleted
+ dw->Deleted = true;
+
+ /// Delete the DirWatcherGeneric
+ efSAFE_DELETE( dw );
+
+ /// Remove the directory from the map
+ Directories.erase( dit->first );
+ }
+}
+
+void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir )
+{
+ FileSystem::dirRemoveSlashAtEnd( oldDir );
+ oldDir = FileSystem::fileNameFromPath( oldDir );
+
+ FileSystem::dirRemoveSlashAtEnd( newDir );
+ newDir = FileSystem::fileNameFromPath( newDir );
+
+ DirWatcherGeneric * dw = NULL;
+ DirWatchMap::iterator dit;
+
+ /// Directory existed?
+ dit = Directories.find( oldDir );
+
+ if ( dit != Directories.end() )
+ {
+ dw = dit->second;
+
+ /// Remove the directory from the map
+ Directories.erase( dit->first );
+
+ Directories[ newDir ] = dw;
+
+ dw->resetDirectory( newDir );
+ }
+}
+
+bool DirWatcherGeneric::pathInWatches( std::string path )
+{
+ if ( DirSnap.DirectoryInfo.Filepath == path )
+ {
+ return true;
+ }
+
+ for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ )
+ {
+ if ( it->second->pathInWatches( path ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/dep/efsw/src/efsw/DirWatcherGeneric.hpp b/dep/efsw/src/efsw/DirWatcherGeneric.hpp
new file mode 100644
index 00000000000..a7581904422
--- /dev/null
+++ b/dep/efsw/src/efsw/DirWatcherGeneric.hpp
@@ -0,0 +1,55 @@
+#ifndef EFSW_DIRWATCHERGENERIC_HPP
+#define EFSW_DIRWATCHERGENERIC_HPP
+
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileInfo.hpp>
+#include <efsw/DirectorySnapshot.hpp>
+#include <map>
+
+namespace efsw {
+
+class DirWatcherGeneric
+{
+ public:
+ typedef std::map<std::string, DirWatcherGeneric*> DirWatchMap;
+
+ DirWatcherGeneric * Parent;
+ WatcherGeneric * Watch;
+ DirectorySnapshot DirSnap;
+ DirWatchMap Directories;
+ bool Recursive;
+
+ DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles = false );
+
+ ~DirWatcherGeneric();
+
+ void watch( bool reportOwnChange = false );
+
+ void watchDir( std::string& dir );
+
+ static bool isDir( const std::string& directory );
+
+ bool pathInWatches( std::string path );
+
+ void addChilds( bool reportNewFiles = true );
+
+ DirWatcherGeneric * findDirWatcher( std::string dir );
+
+ DirWatcherGeneric * findDirWatcherFast( std::string dir );
+ protected:
+ bool Deleted;
+
+ DirWatcherGeneric * createDirectory( std::string newdir );
+
+ void removeDirectory( std::string dir );
+
+ void moveDirectory( std::string oldDir, std::string newDir );
+
+ void resetDirectory( std::string directory );
+
+ void handleAction( const std::string& filename, unsigned long action, std::string oldFilename = "");
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/DirectorySnapshot.cpp b/dep/efsw/src/efsw/DirectorySnapshot.cpp
new file mode 100644
index 00000000000..c0ef747548a
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshot.cpp
@@ -0,0 +1,261 @@
+#include <efsw/DirectorySnapshot.hpp>
+#include <efsw/FileSystem.hpp>
+
+namespace efsw {
+
+DirectorySnapshot::DirectorySnapshot()
+{
+}
+
+DirectorySnapshot::DirectorySnapshot( std::string directory )
+{
+ init( directory );
+}
+
+DirectorySnapshot::~DirectorySnapshot()
+{
+}
+
+void DirectorySnapshot::init( std::string directory )
+{
+ setDirectoryInfo( directory );
+ initFiles();
+}
+
+bool DirectorySnapshot::exists()
+{
+ return DirectoryInfo.exists();
+}
+
+void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff )
+{
+ FileInfo fi;
+
+ for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ )
+ {
+ fi = it->second;
+
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsDeleted.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesDeleted.push_back( fi );
+ }
+ }
+}
+
+void DirectorySnapshot::setDirectoryInfo( std::string directory )
+{
+ DirectoryInfo = FileInfo( directory );
+}
+
+void DirectorySnapshot::initFiles()
+{
+ Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath );
+
+ FileInfoMap::iterator it = Files.begin();
+ std::list<std::string> eraseFiles;
+
+ /// Remove all non regular files and non directories
+ for ( ; it != Files.end(); it++ )
+ {
+ if ( !it->second.isRegularFile() && !it->second.isDirectory() )
+ {
+ eraseFiles.push_back( it->first );
+ }
+ }
+
+ for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); eit++ )
+ {
+ Files.erase( *eit );
+ }
+}
+
+DirectorySnapshotDiff DirectorySnapshot::scan()
+{
+ DirectorySnapshotDiff Diff;
+
+ Diff.clear();
+
+ FileInfo curFI( DirectoryInfo.Filepath );
+
+ Diff.DirChanged = DirectoryInfo != curFI;
+
+ if ( Diff.DirChanged )
+ {
+ DirectoryInfo = curFI;
+ }
+
+ /// If the directory was erased, create the events for files and directories deletion
+ if ( !curFI.exists() )
+ {
+ deleteAll( Diff );
+
+ return Diff;
+ }
+
+ FileInfoMap files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath );
+
+ if ( files.empty() && Files.empty() )
+ {
+ return Diff;
+ }
+
+ FileInfo fi;
+ FileInfoMap FilesCpy;
+ FileInfoMap::iterator it;
+ FileInfoMap::iterator fiIt;
+
+ if ( Diff.DirChanged )
+ {
+ FilesCpy = Files;
+ }
+
+ for ( it = files.begin(); it != files.end(); it++ )
+ {
+ fi = it->second;
+
+ /// File existed before?
+ fiIt = Files.find( it->first );
+
+ if ( fiIt != Files.end() )
+ {
+ /// Erase from the file list copy
+ FilesCpy.erase( it->first );
+
+ /// File changed?
+ if ( (*fiIt).second != fi )
+ {
+ /// Update the new file info
+ Files[ it->first ] = fi;
+
+ /// handle modified event
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsModified.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesModified.push_back( fi );
+ }
+ }
+ }
+ /// Only add regular files or directories
+ else if ( fi.isRegularFile() || fi.isDirectory() )
+ {
+ /// New file found
+ Files[ it->first ] = fi;
+
+ FileInfoMap::iterator fit;
+ std::string oldFile = "";
+
+ /// Check if the same inode already existed
+ if ( ( fit = nodeInFiles( fi ) ) != Files.end() )
+ {
+ oldFile = fit->first;
+
+ /// Avoid firing a Delete event
+ FilesCpy.erase( fit->first );
+
+ /// Delete the old file name
+ Files.erase( fit->first );
+
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsMoved.push_back( std::make_pair( oldFile, fi ) );
+ }
+ else
+ {
+ Diff.FilesMoved.push_back( std::make_pair( oldFile, fi ) );
+ }
+ }
+ else
+ {
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsCreated.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesCreated.push_back( fi );
+ }
+ }
+ }
+ }
+
+ if ( !Diff.DirChanged )
+ {
+ return Diff;
+ }
+
+ /// The files or directories that remains were deleted
+ for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ )
+ {
+ fi = it->second;
+
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsDeleted.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesDeleted.push_back( fi );
+ }
+
+ /// Remove the file or directory from the list of files
+ Files.erase( it->first );
+ }
+
+ return Diff;
+}
+
+FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi )
+{
+ FileInfoMap::iterator it;
+
+ if ( FileInfo::inodeSupported() )
+ {
+ for ( it = Files.begin(); it != Files.end(); it++ )
+ {
+ if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath )
+ {
+ return it;
+ }
+ }
+ }
+
+ return Files.end();
+}
+
+void DirectorySnapshot::addFile( std::string path )
+{
+ std::string name( FileSystem::fileNameFromPath( path ) );
+ Files[ name ] = FileInfo( path );
+}
+
+void DirectorySnapshot::removeFile( std::string path )
+{
+ std::string name( FileSystem::fileNameFromPath( path ) );
+
+ FileInfoMap::iterator it = Files.find( name );
+
+ if ( Files.end() != it )
+ {
+ Files.erase( it );
+ }
+}
+
+void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath )
+{
+ removeFile( oldPath );
+ addFile( newPath );
+}
+
+void DirectorySnapshot::updateFile(std::string path)
+{
+ addFile( path );
+}
+
+}
diff --git a/dep/efsw/src/efsw/DirectorySnapshot.hpp b/dep/efsw/src/efsw/DirectorySnapshot.hpp
new file mode 100644
index 00000000000..1ada66fe980
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshot.hpp
@@ -0,0 +1,46 @@
+#ifndef EFSW_DIRECTORYSNAPSHOT_HPP
+#define EFSW_DIRECTORYSNAPSHOT_HPP
+
+#include <efsw/DirectorySnapshotDiff.hpp>
+
+namespace efsw {
+
+class DirectorySnapshot
+{
+ public:
+ FileInfo DirectoryInfo;
+ FileInfoMap Files;
+
+ void setDirectoryInfo( std::string directory );
+
+ DirectorySnapshot();
+
+ DirectorySnapshot( std::string directory );
+
+ ~DirectorySnapshot();
+
+ void init( std::string directory );
+
+ bool exists();
+
+ DirectorySnapshotDiff scan();
+
+ FileInfoMap::iterator nodeInFiles( FileInfo& fi );
+
+ void addFile( std::string path );
+
+ void removeFile( std::string path );
+
+ void moveFile( std::string oldPath, std::string newPath );
+
+ void updateFile( std::string path );
+ protected:
+ void initFiles();
+
+ void deleteAll( DirectorySnapshotDiff &Diff );
+};
+
+}
+
+#endif
+
diff --git a/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp b/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp
new file mode 100644
index 00000000000..eabc6fdbda1
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp
@@ -0,0 +1,29 @@
+#include <efsw/DirectorySnapshotDiff.hpp>
+
+namespace efsw {
+
+void DirectorySnapshotDiff::clear()
+{
+ FilesCreated.clear();
+ FilesModified.clear();
+ FilesMoved.clear();
+ FilesDeleted.clear();
+ DirsCreated.clear();
+ DirsModified.clear();
+ DirsMoved.clear();
+ DirsDeleted.clear();
+}
+
+bool DirectorySnapshotDiff::changed()
+{
+ return !FilesCreated.empty() ||
+ !FilesModified.empty() ||
+ !FilesMoved.empty() ||
+ !FilesDeleted.empty() ||
+ !DirsCreated.empty() ||
+ !DirsModified.empty() ||
+ !DirsMoved.empty() ||
+ !DirsDeleted.empty();
+}
+
+}
diff --git a/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp b/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp
new file mode 100644
index 00000000000..042de9ce02c
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp
@@ -0,0 +1,35 @@
+#ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP
+#define EFSW_DIRECTORYSNAPSHOTDIFF_HPP
+
+#include <efsw/FileInfo.hpp>
+
+namespace efsw {
+
+class DirectorySnapshotDiff
+{
+ public:
+ FileInfoList FilesDeleted;
+ FileInfoList FilesCreated;
+ FileInfoList FilesModified;
+ MovedList FilesMoved;
+ FileInfoList DirsDeleted;
+ FileInfoList DirsCreated;
+ FileInfoList DirsModified;
+ MovedList DirsMoved;
+ bool DirChanged;
+
+ void clear();
+
+ bool changed();
+};
+
+#define DiffIterator( FileInfoListName ) it = Diff.FileInfoListName.begin(); \
+ for ( ; it != Diff.FileInfoListName.end(); it++ )
+
+#define DiffMovedIterator( MovedListName ) mit = Diff.MovedListName.begin(); \
+ for ( ; mit != Diff.MovedListName.end(); mit++ )
+
+}
+
+#endif
+
diff --git a/dep/efsw/src/efsw/FileInfo.cpp b/dep/efsw/src/efsw/FileInfo.cpp
new file mode 100644
index 00000000000..7003afc2a15
--- /dev/null
+++ b/dep/efsw/src/efsw/FileInfo.cpp
@@ -0,0 +1,274 @@
+#include <efsw/FileInfo.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/String.hpp>
+
+#ifndef _DARWIN_FEATURE_64_BIT_INODE
+#define _DARWIN_FEATURE_64_BIT_INODE
+#endif
+
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <stdlib.h>
+
+#ifdef EFSW_COMPILER_MSVC
+ #ifndef S_ISDIR
+ #define S_ISDIR(f) ((f)&_S_IFDIR)
+ #endif
+
+ #ifndef S_ISREG
+ #define S_ISREG(f) ((f)&_S_IFREG)
+ #endif
+
+ #ifndef S_ISRDBL
+ #define S_ISRDBL(f) ((f)&_S_IREAD)
+ #endif
+#else
+ #include <unistd.h>
+
+ #ifndef S_ISRDBL
+ #define S_ISRDBL(f) ((f)&S_IRUSR)
+ #endif
+#endif
+
+namespace efsw {
+
+bool FileInfo::exists( const std::string& filePath )
+{
+ FileInfo fi( filePath );
+ return fi.exists();
+}
+
+bool FileInfo::isLink( const std::string& filePath )
+{
+ FileInfo fi( filePath, true );
+ return fi.isLink();
+}
+
+bool FileInfo::inodeSupported()
+{
+ #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ return true;
+ #else
+ return false;
+ #endif
+}
+
+FileInfo::FileInfo() :
+ ModificationTime(0),
+ OwnerId(0),
+ GroupId(0),
+ Permissions(0),
+ Inode(0)
+{}
+
+FileInfo::FileInfo( const std::string& filepath ) :
+ Filepath( filepath ),
+ ModificationTime(0),
+ OwnerId(0),
+ GroupId(0),
+ Permissions(0),
+ Inode(0)
+{
+ getInfo();
+}
+
+FileInfo::FileInfo( const std::string& filepath, bool linkInfo ) :
+ Filepath( filepath ),
+ ModificationTime(0),
+ OwnerId(0),
+ GroupId(0),
+ Permissions(0),
+ Inode(0)
+{
+ if ( linkInfo )
+ {
+ getRealInfo();
+ }
+ else
+ {
+ getInfo();
+ }
+}
+
+void FileInfo::getInfo()
+{
+ #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+ if ( Filepath.size() == 3 && Filepath[1] == ':' && Filepath[2] == FileSystem::getOSSlash() )
+ {
+ Filepath += FileSystem::getOSSlash();
+ }
+ #endif
+
+ /// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a path slash
+ bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirRemoveSlashAtEnd( Filepath );
+ }
+
+ #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ struct stat st;
+ int res = stat( Filepath.c_str(), &st );
+ #else
+ struct _stat st;
+ int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
+ #endif
+
+ if ( 0 == res )
+ {
+ ModificationTime = st.st_mtime;
+ Size = st.st_size;
+ OwnerId = st.st_uid;
+ GroupId = st.st_gid;
+ Permissions = st.st_mode;
+ Inode = st.st_ino;
+ }
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirAddSlashAtEnd( Filepath );
+ }
+}
+
+void FileInfo::getRealInfo()
+{
+ bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirRemoveSlashAtEnd( Filepath );
+ }
+
+ #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ struct stat st;
+ int res = lstat( Filepath.c_str(), &st );
+ #else
+ struct _stat st;
+ int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
+ #endif
+
+ if ( 0 == res )
+ {
+ ModificationTime = st.st_mtime;
+ Size = st.st_size;
+ OwnerId = st.st_uid;
+ GroupId = st.st_gid;
+ Permissions = st.st_mode;
+ Inode = st.st_ino;
+ }
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirAddSlashAtEnd( Filepath );
+ }
+}
+
+bool FileInfo::operator==( const FileInfo& Other ) const
+{
+ return ( ModificationTime == Other.ModificationTime &&
+ Size == Other.Size &&
+ OwnerId == Other.OwnerId &&
+ GroupId == Other.GroupId &&
+ Permissions == Other.Permissions &&
+ Inode == Other.Inode
+ );
+}
+
+bool FileInfo::isDirectory()
+{
+ return 0 != S_ISDIR(Permissions);
+}
+
+bool FileInfo::isRegularFile()
+{
+ return 0 != S_ISREG(Permissions);
+}
+
+bool FileInfo::isReadable()
+{
+ return 0 != S_ISRDBL(Permissions);
+}
+
+bool FileInfo::isLink()
+{
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ return S_ISLNK(Permissions);
+#else
+ return false;
+#endif
+}
+
+std::string FileInfo::linksTo()
+{
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ if ( isLink() )
+ {
+ char * ch = realpath( Filepath.c_str(), NULL);
+
+ if ( NULL != ch )
+ {
+ std::string tstr( ch );
+
+ free( ch );
+
+ return tstr;
+ }
+ }
+#endif
+ return std::string("");
+}
+
+bool FileInfo::exists()
+{
+ bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirRemoveSlashAtEnd(Filepath);
+ }
+
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ struct stat st;
+ int res = stat( Filepath.c_str(), &st );
+#else
+ struct _stat st;
+ int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
+#endif
+
+ if (slashAtEnd)
+ {
+ FileSystem::dirAddSlashAtEnd(Filepath);
+ }
+
+ return 0 == res;
+}
+
+FileInfo& FileInfo::operator=( const FileInfo& Other )
+{
+ this->Filepath = Other.Filepath;
+ this->Size = Other.Size;
+ this->ModificationTime = Other.ModificationTime;
+ this->GroupId = Other.GroupId;
+ this->OwnerId = Other.OwnerId;
+ this->Permissions = Other.Permissions;
+ this->Inode = Other.Inode;
+ return *this;
+}
+
+bool FileInfo::sameInode( const FileInfo& Other ) const
+{
+ return inodeSupported() && Inode == Other.Inode;
+}
+
+bool FileInfo::operator!=( const FileInfo& Other ) const
+{
+ return !(*this == Other);
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileInfo.hpp b/dep/efsw/src/efsw/FileInfo.hpp
new file mode 100644
index 00000000000..45cca6a7953
--- /dev/null
+++ b/dep/efsw/src/efsw/FileInfo.hpp
@@ -0,0 +1,66 @@
+#ifndef EFSW_FILEINFO_HPP
+#define EFSW_FILEINFO_HPP
+
+#include <efsw/base.hpp>
+#include <string>
+#include <map>
+#include <list>
+
+namespace efsw {
+
+class FileInfo
+{
+ public:
+ static bool exists( const std::string& filePath );
+
+ static bool isLink( const std::string& filePath );
+
+ static bool inodeSupported();
+
+ FileInfo();
+
+ FileInfo( const std::string& filepath );
+
+ FileInfo( const std::string& filepath, bool linkInfo );
+
+ bool operator==( const FileInfo& Other ) const;
+
+ bool operator!=( const FileInfo& Other ) const;
+
+ FileInfo& operator=( const FileInfo& Other );
+
+ bool isDirectory();
+
+ bool isRegularFile();
+
+ bool isReadable();
+
+ bool sameInode( const FileInfo& Other ) const;
+
+ bool isLink();
+
+ std::string linksTo();
+
+ bool exists();
+
+ void getInfo();
+
+ void getRealInfo();
+
+ std::string Filepath;
+ Uint64 ModificationTime;
+ Uint64 Size;
+ Uint32 OwnerId;
+ Uint32 GroupId;
+ Uint32 Permissions;
+ Uint64 Inode;
+};
+
+typedef std::map<std::string, FileInfo> FileInfoMap;
+typedef std::list<FileInfo> FileInfoList;
+typedef std::list< std::pair< std::string, FileInfo> > MovedList;
+
+}
+
+#endif
+
diff --git a/dep/efsw/src/efsw/FileSystem.cpp b/dep/efsw/src/efsw/FileSystem.cpp
new file mode 100644
index 00000000000..e3afa0b4046
--- /dev/null
+++ b/dep/efsw/src/efsw/FileSystem.cpp
@@ -0,0 +1,124 @@
+#include <efsw/FileSystem.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+#if EFSW_OS == EFSW_OS_MACOSX
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace efsw {
+
+bool FileSystem::isDirectory( const std::string& path )
+{
+ return Platform::FileSystem::isDirectory( path );
+}
+
+FileInfoMap FileSystem::filesInfoFromPath( std::string path ) {
+ dirAddSlashAtEnd( path );
+
+ return Platform::FileSystem::filesInfoFromPath( path );
+}
+
+char FileSystem::getOSSlash()
+{
+ return Platform::FileSystem::getOSSlash();
+}
+
+bool FileSystem::slashAtEnd( std::string &dir )
+{
+ return ( dir.size() && dir[ dir.size() - 1 ] == getOSSlash() );
+}
+
+void FileSystem::dirAddSlashAtEnd( std::string& dir )
+{
+ if ( dir.size() > 1 && dir[ dir.size() - 1 ] != getOSSlash() )
+ {
+ dir.push_back( getOSSlash() );
+ }
+}
+
+void FileSystem::dirRemoveSlashAtEnd( std::string& dir )
+{
+ if ( dir.size() > 1 && dir[ dir.size() - 1 ] == getOSSlash() )
+ {
+ dir.erase( dir.size() - 1 );
+ }
+}
+
+std::string FileSystem::fileNameFromPath( std::string filepath )
+{
+ dirRemoveSlashAtEnd( filepath );
+
+ size_t pos = filepath.find_last_of( getOSSlash() );
+
+ if ( pos != std::string::npos )
+ {
+ return filepath.substr( pos + 1 );
+ }
+
+ return filepath;
+}
+
+std::string FileSystem::pathRemoveFileName( std::string filepath )
+{
+ dirRemoveSlashAtEnd( filepath );
+
+ size_t pos = filepath.find_last_of( getOSSlash() );
+
+ if ( pos != std::string::npos )
+ {
+ return filepath.substr( 0, pos + 1 );
+ }
+
+ return filepath;
+}
+
+std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath )
+{
+ FileSystem::dirRemoveSlashAtEnd( dir );
+ FileInfo fi( dir, true );
+
+ /// Check with lstat and see if it's a link
+ if ( fi.isLink() )
+ {
+ /// get the real path of the link
+ std::string link( fi.linksTo() );
+
+ /// get the current path of the directory without the link dir path
+ curPath = FileSystem::pathRemoveFileName( dir );
+
+ /// ensure that ends with the os directory slash
+ FileSystem::dirAddSlashAtEnd( link );
+
+ return link;
+ }
+
+ /// if it's not a link return nothing
+ return "";
+}
+
+std::string FileSystem::precomposeFileName( const std::string& name )
+{
+#if EFSW_OS == EFSW_OS_MACOSX
+ CFStringRef cfStringRef = CFStringCreateWithCString(kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8);
+ CFMutableStringRef cfMutable = CFStringCreateMutableCopy(NULL, 0, cfStringRef);
+
+ CFStringNormalize(cfMutable,kCFStringNormalizationFormC);
+
+ char c_str[255 + 1];
+ CFStringGetCString(cfMutable, c_str, sizeof(c_str)-1, kCFStringEncodingUTF8);
+
+ CFRelease(cfStringRef);
+ CFRelease(cfMutable);
+
+ return std::string(c_str);
+#else
+ return name;
+#endif
+}
+
+bool FileSystem::isRemoteFS( const std::string& directory )
+{
+ return Platform::FileSystem::isRemoteFS( directory );
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileSystem.hpp b/dep/efsw/src/efsw/FileSystem.hpp
new file mode 100644
index 00000000000..4e2e1aeb7cd
--- /dev/null
+++ b/dep/efsw/src/efsw/FileSystem.hpp
@@ -0,0 +1,40 @@
+#ifndef EFSW_FILESYSTEM_HPP
+#define EFSW_FILESYSTEM_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/FileInfo.hpp>
+#include <map>
+
+namespace efsw {
+
+class FileSystem
+{
+ public:
+ static bool isDirectory( const std::string& path );
+
+ static FileInfoMap filesInfoFromPath( std::string path );
+
+ static char getOSSlash();
+
+ static bool slashAtEnd( std::string& dir );
+
+ static void dirAddSlashAtEnd( std::string& dir );
+
+ static void dirRemoveSlashAtEnd( std::string& dir );
+
+ static std::string fileNameFromPath( std::string filepath );
+
+ static std::string pathRemoveFileName( std::string filepath );
+
+ static void realPath( std::string curdir, std::string& path );
+
+ static std::string getLinkRealPath( std::string dir, std::string& curPath );
+
+ static std::string precomposeFileName(const std::string& name);
+
+ static bool isRemoteFS( const std::string& directory );
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcher.cpp b/dep/efsw/src/efsw/FileWatcher.cpp
new file mode 100644
index 00000000000..e33d5ec46fb
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcher.cpp
@@ -0,0 +1,145 @@
+#include <efsw/efsw.hpp>
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/FileWatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+# include <efsw/FileWatcherWin32.hpp>
+# define FILEWATCHER_IMPL FileWatcherWin32
+# define BACKEND_NAME "Win32"
+#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
+# include <efsw/FileWatcherInotify.hpp>
+# define FILEWATCHER_IMPL FileWatcherInotify
+# define BACKEND_NAME "Inotify"
+#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE
+# include <efsw/FileWatcherKqueue.hpp>
+# define FILEWATCHER_IMPL FileWatcherKqueue
+# define BACKEND_NAME "Kqueue"
+#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+# include <efsw/FileWatcherFSEvents.hpp>
+# define FILEWATCHER_IMPL FileWatcherFSEvents
+# define BACKEND_NAME "FSEvents"
+#else
+# define FILEWATCHER_IMPL FileWatcherGeneric
+# define BACKEND_NAME "Generic"
+#endif
+
+#include <efsw/Debug.hpp>
+
+namespace efsw {
+
+FileWatcher::FileWatcher() :
+ mFollowSymlinks(false),
+ mOutOfScopeLinks(false)
+{
+ efDEBUG( "Using backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FILEWATCHER_IMPL( this );
+
+ if ( !mImpl->initOK() )
+ {
+ efSAFE_DELETE( mImpl );
+
+ efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FileWatcherGeneric( this );
+ }
+}
+
+FileWatcher::FileWatcher( bool useGenericFileWatcher ) :
+ mFollowSymlinks(false),
+ mOutOfScopeLinks(false)
+{
+ if ( useGenericFileWatcher )
+ {
+ efDEBUG( "Using backend: Generic\n" );
+
+ mImpl = new FileWatcherGeneric( this );
+ }
+ else
+ {
+ efDEBUG( "Using backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FILEWATCHER_IMPL( this );
+
+ if ( !mImpl->initOK() )
+ {
+ efSAFE_DELETE( mImpl );
+
+ efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FileWatcherGeneric( this );
+ }
+ }
+}
+
+FileWatcher::~FileWatcher()
+{
+ efSAFE_DELETE( mImpl );
+}
+
+WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher)
+{
+ if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) )
+ {
+ return mImpl->addWatch(directory, watcher, false);
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, directory );
+ }
+}
+
+WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) )
+ {
+ return mImpl->addWatch(directory, watcher, recursive);
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, directory );
+ }
+}
+
+void FileWatcher::removeWatch(const std::string& directory)
+{
+ mImpl->removeWatch(directory);
+}
+
+void FileWatcher::removeWatch(WatchID watchid)
+{
+ mImpl->removeWatch(watchid);
+}
+
+void FileWatcher::watch()
+{
+ mImpl->watch();
+}
+
+std::list<std::string> FileWatcher::directories()
+{
+ return mImpl->directories();
+}
+
+void FileWatcher::followSymlinks( bool follow )
+{
+ mFollowSymlinks = follow;
+}
+
+const bool& FileWatcher::followSymlinks() const
+{
+ return mFollowSymlinks;
+}
+
+void FileWatcher::allowOutOfScopeLinks( bool allow )
+{
+ mOutOfScopeLinks = allow;
+}
+
+const bool& FileWatcher::allowOutOfScopeLinks() const
+{
+ return mOutOfScopeLinks;
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileWatcherCWrapper.cpp b/dep/efsw/src/efsw/FileWatcherCWrapper.cpp
new file mode 100644
index 00000000000..2739e756bb2
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherCWrapper.cpp
@@ -0,0 +1,132 @@
+#include <efsw/efsw.h>
+#include <efsw/efsw.hpp>
+#include <vector>
+
+#define TOBOOL(i) ((i) == 0 ? false : true)
+
+/*************************************************************************************************/
+class Watcher_CAPI : public efsw::FileWatchListener
+{
+public:
+ efsw_watcher mWatcher;
+ efsw_pfn_fileaction_callback mFn;
+ void* mParam;
+public:
+ Watcher_CAPI(efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param)
+ {
+ mWatcher = watcher;
+ mFn = fn;
+ mParam = param;
+ }
+
+ void handleFileAction(efsw::WatchID watchid, const std::string& dir, const std::string& filename,
+ efsw::Action action, std::string oldFilename = "")
+ {
+ mFn(mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action,
+ oldFilename.c_str(), mParam );
+ }
+};
+
+/*************************************************************************************************
+ * globals
+ */
+static std::vector<Watcher_CAPI*> g_callbacks;
+
+Watcher_CAPI* find_callback(efsw_watcher watcher, efsw_pfn_fileaction_callback fn)
+{
+ for (std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); i++ )
+ {
+ Watcher_CAPI* callback = *i;
+
+ if (callback->mFn == fn && callback->mWatcher == watcher)
+ return *i;
+ }
+
+ return NULL;
+}
+
+Watcher_CAPI* remove_callback(efsw_watcher watcher)
+{
+ std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin();
+
+ while (i != g_callbacks.end()) {
+ Watcher_CAPI* callback = *i;
+
+ if (callback->mWatcher == watcher)
+ i = g_callbacks.erase(i);
+ else
+ i++;
+ }
+
+ return NULL;
+}
+
+
+/*************************************************************************************************/
+efsw_watcher efsw_create(int generic_mode)
+{
+ return (efsw_watcher)new efsw::FileWatcher(TOBOOL(generic_mode));
+}
+
+void efsw_release(efsw_watcher watcher)
+{
+ remove_callback(watcher);
+ delete (efsw::FileWatcher*)watcher;
+}
+
+const char* efsw_getlasterror()
+{
+ static std::string log_str;
+ log_str = efsw::Errors::Log::getLastErrorLog();
+ return log_str.c_str();
+}
+
+efsw_watchid efsw_addwatch(efsw_watcher watcher, const char* directory,
+ efsw_pfn_fileaction_callback callback_fn, int recursive, void * param)
+{
+ Watcher_CAPI* callback = find_callback(watcher, callback_fn);
+
+ if (callback == NULL) {
+ callback = new Watcher_CAPI(watcher, callback_fn, param);
+ g_callbacks.push_back(callback);
+ }
+
+ return ((efsw::FileWatcher*)watcher)->addWatch(std::string(directory), callback,
+ TOBOOL(recursive));
+}
+
+void efsw_removewatch(efsw_watcher watcher, const char* directory)
+{
+ ((efsw::FileWatcher*)watcher)->removeWatch(std::string(directory));
+}
+
+void efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid)
+{
+ ((efsw::FileWatcher*)watcher)->removeWatch(watchid);
+}
+
+void efsw_watch(efsw_watcher watcher)
+{
+ ((efsw::FileWatcher*)watcher)->watch();
+}
+
+void efsw_follow_symlinks(efsw_watcher watcher, int enable)
+{
+ ((efsw::FileWatcher*)watcher)->followSymlinks(TOBOOL(enable));
+}
+
+int efsw_follow_symlinks_isenabled(efsw_watcher watcher)
+{
+ return (int)((efsw::FileWatcher*)watcher)->followSymlinks();
+}
+
+void efsw_allow_outofscopelinks(efsw_watcher watcher, int allow)
+{
+ ((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks(TOBOOL(allow));
+}
+
+int efsw_outofscopelinks_isallowed(efsw_watcher watcher)
+{
+ return (int)((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks();
+}
+
diff --git a/dep/efsw/src/efsw/FileWatcherFSEvents.cpp b/dep/efsw/src/efsw/FileWatcherFSEvents.cpp
new file mode 100644
index 00000000000..40156674132
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherFSEvents.cpp
@@ -0,0 +1,278 @@
+#include <efsw/FileWatcherFSEvents.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/Debug.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <sys/utsname.h>
+
+namespace efsw
+{
+
+int getOSXReleaseNumber()
+{
+ static int osxR = -1;
+
+ if ( -1 == osxR )
+ {
+ struct utsname os;
+
+ if ( -1 != uname( &os ) ) {
+ std::string release( os.release );
+
+ size_t pos = release.find_first_of( '.' );
+
+ if ( pos != std::string::npos )
+ {
+ release = release.substr( 0, pos );
+ }
+
+ int rel = 0;
+
+ if ( String::fromString<int>( rel, release ) )
+ {
+ osxR = rel;
+ }
+ }
+ }
+
+ return osxR;
+}
+
+bool FileWatcherFSEvents::isGranular()
+{
+ return getOSXReleaseNumber() >= 11;
+}
+
+void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef,
+ void *userData,
+ size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[] )
+{
+ WatcherFSEvents * watcher = static_cast<WatcherFSEvents*>( userData );
+
+ std::vector<FSEvent> events;
+ events.reserve( numEvents );
+
+ for ( size_t i = 0; i < numEvents; i++ )
+ {
+ events.push_back( FSEvent( std::string( ((char**)eventPaths)[i] ), (long)eventFlags[i], (Uint64)eventIds[i] ) );
+ }
+
+ watcher->handleActions( events );
+
+ watcher->process();
+
+ efDEBUG( "\n" );
+}
+
+FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mRunLoopRef( NULL ),
+ mLastWatchID(0),
+ mThread( NULL )
+{
+ mInitOK = true;
+
+ watch();
+}
+
+FileWatcherFSEvents::~FileWatcherFSEvents()
+{
+ WatchMap::iterator iter = mWatches.begin();
+
+ for( ; iter != mWatches.end(); ++iter )
+ {
+ WatcherFSEvents * watch = iter->second;
+
+ efSAFE_DELETE( watch );
+ }
+
+ mWatches.clear();
+
+ mInitOK = false;
+
+ if ( NULL != mRunLoopRef )
+ {
+ CFRunLoopStop( mRunLoopRef );
+ }
+
+ efSAFE_DELETE( mThread );
+}
+
+WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive )
+{
+ /// Wait to the RunLoopRef to be ready
+ while ( NULL == mRunLoopRef )
+ {
+ System::sleep( 1 );
+ }
+
+ std::string dir( directory );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+
+ /// Check if the directory is a symbolic link
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ mLastWatchID++;
+
+ WatcherFSEvents * pWatch = new WatcherFSEvents();
+ pWatch->Listener = watcher;
+ pWatch->ID = mLastWatchID;
+ pWatch->Directory = dir;
+ pWatch->Recursive = recursive;
+ pWatch->FWatcher = this;
+
+ pWatch->init();
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, pWatch));
+ mWatchesLock.unlock();
+
+ return pWatch->ID;
+}
+
+void FileWatcherFSEvents::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if( directory == iter->second->Directory )
+ {
+ removeWatch( iter->second->ID );
+ return;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherFSEvents::removeWatch(WatchID watchid)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.find( watchid );
+
+ if( iter == mWatches.end() )
+ return;
+
+ WatcherFSEvents * watch = iter->second;
+
+ mWatches.erase( iter );
+
+ efDEBUG( "Removed watch %s\n", watch->Directory.c_str() );
+
+ efSAFE_DELETE( watch );
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherFSEvents::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherFSEvents::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherFSEvents::run()
+{
+ mRunLoopRef = CFRunLoopGetCurrent();
+
+ while ( mInitOK )
+ {
+ if ( !mNeedInit.empty() )
+ {
+ for ( std::list<WatcherFSEvents*>::iterator it = mNeedInit.begin(); it != mNeedInit.end(); it++ )
+ {
+ (*it)->initAsync();
+ }
+
+ mNeedInit.clear();
+ }
+
+ CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut );
+ }
+}
+
+void FileWatcherFSEvents::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+ /// Not used
+}
+
+std::list<std::string> FileWatcherFSEvents::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ dirs.push_back( std::string( it->second->Directory ) );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherFSEvents::pathInWatches( const std::string& path )
+{
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherFSEvents.hpp b/dep/efsw/src/efsw/FileWatcherFSEvents.hpp
new file mode 100644
index 00000000000..6aafbc0b5ea
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherFSEvents.hpp
@@ -0,0 +1,107 @@
+#ifndef EFSW_FILEWATCHERFSEVENTS_HPP
+#define EFSW_FILEWATCHERFSEVENTS_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <efsw/WatcherFSEvents.hpp>
+#include <map>
+#include <list>
+#include <vector>
+
+namespace efsw
+{
+
+/* OSX < 10.7 has no file events */
+/* So i declare the events constants */
+enum FSEventEvents
+{
+ efswFSEventStreamCreateFlagFileEvents = 0x00000010,
+ efswFSEventStreamEventFlagItemCreated = 0x00000100,
+ efswFSEventStreamEventFlagItemRemoved = 0x00000200,
+ efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400,
+ efswFSEventStreamEventFlagItemRenamed = 0x00000800,
+ efswFSEventStreamEventFlagItemModified = 0x00001000,
+ efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000,
+ efswFSEventStreamEventFlagItemChangeOwner = 0x00004000,
+ efswFSEventStreamEventFlagItemXattrMod = 0x00008000,
+ efswFSEventStreamEventFlagItemIsFile = 0x00010000,
+ efswFSEventStreamEventFlagItemIsDir = 0x00020000,
+ efswFSEventStreamEventFlagItemIsSymlink = 0x00040000,
+ efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod |
+ efswFSEventStreamEventFlagItemModified |
+ efswFSEventStreamEventFlagItemInodeMetaMod |
+ efswFSEventStreamEventFlagItemChangeOwner |
+ efswFSEventStreamEventFlagItemXattrMod
+};
+
+/// Implementation for Win32 based on ReadDirectoryChangesW.
+/// @class FileWatcherFSEvents
+class FileWatcherFSEvents : public FileWatcherImpl
+{
+ friend class WatcherFSEvents;
+ public:
+ /// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 )
+ static bool isGranular();
+
+ /// type for a map from WatchID to WatcherWin32 pointer
+ typedef std::map<WatchID, WatcherFSEvents*> WatchMap;
+
+ FileWatcherFSEvents( FileWatcher * parent );
+
+ virtual ~FileWatcherFSEvents();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ static void FSEventCallback( ConstFSEventStreamRef streamRef,
+ void *userData,
+ size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]
+ );
+
+ CFRunLoopRef mRunLoopRef;
+
+ /// Vector of WatcherWin32 pointers
+ WatchMap mWatches;
+
+ /// The last watchid
+ WatchID mLastWatchID;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ bool pathInWatches( const std::string& path );
+
+ std::list<WatcherFSEvents*> mNeedInit;
+ private:
+ void run();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherGeneric.cpp b/dep/efsw/src/efsw/FileWatcherGeneric.cpp
new file mode 100644
index 00000000000..1534b6a9279
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherGeneric.cpp
@@ -0,0 +1,197 @@
+#include <efsw/FileWatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+
+namespace efsw
+{
+
+FileWatcherGeneric::FileWatcherGeneric( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mThread( NULL ),
+ mLastWatchID( 0 )
+{
+ mInitOK = true;
+ mIsGeneric = true;
+}
+
+FileWatcherGeneric::~FileWatcherGeneric()
+{
+ mInitOK = false;
+
+ mThread->wait();
+
+ efSAFE_DELETE( mThread );
+
+ /// Delete the watches
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ efSAFE_DELETE( (*it) );
+ }
+}
+
+WatchID FileWatcherGeneric::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+ else if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, dir );
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, dir );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ mLastWatchID++;
+
+ WatcherGeneric * pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive );
+
+ mWatchesLock.lock();
+ mWatches.push_back(pWatch);
+ mWatchesLock.unlock();
+
+ return pWatch->ID;
+}
+
+void FileWatcherGeneric::removeWatch( const std::string& directory )
+{
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Directory == directory )
+ {
+ WatcherGeneric * watch = (*it);
+
+ mWatchesLock.lock();
+
+ mWatches.erase( it );
+
+ efSAFE_DELETE( watch ) ;
+
+ mWatchesLock.unlock();
+
+ return;
+ }
+ }
+}
+
+void FileWatcherGeneric::removeWatch(WatchID watchid)
+{
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( (*it)->ID == watchid )
+ {
+ WatcherGeneric * watch = (*it);
+
+ mWatchesLock.lock();
+
+ mWatches.erase( it );
+
+ efSAFE_DELETE( watch ) ;
+
+ mWatchesLock.unlock();
+
+ return;
+ }
+ }
+}
+
+void FileWatcherGeneric::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherGeneric::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherGeneric::run()
+{
+ do
+ {
+ mWatchesLock.lock();
+
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ (*it)->watch();
+ }
+
+ mWatchesLock.unlock();
+
+ if ( mInitOK ) System::sleep( 1000 );
+ } while ( mInitOK );
+}
+
+void FileWatcherGeneric::handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+ /// Not used
+}
+
+std::list<std::string> FileWatcherGeneric::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ dirs.push_back( (*it)->Directory );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherGeneric::pathInWatches( const std::string& path )
+{
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Directory == path || (*it)->pathInWatches( path ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileWatcherGeneric.hpp b/dep/efsw/src/efsw/FileWatcherGeneric.hpp
new file mode 100644
index 00000000000..fc9826580ab
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherGeneric.hpp
@@ -0,0 +1,59 @@
+#ifndef EFSW_FILEWATCHERGENERIC_HPP
+#define EFSW_FILEWATCHERGENERIC_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/DirWatcherGeneric.hpp>
+#include <list>
+
+namespace efsw
+{
+
+/// Implementation for Generic File Watcher.
+/// @class FileWatcherGeneric
+class FileWatcherGeneric : public FileWatcherImpl
+{
+ public:
+ typedef std::list<WatcherGeneric*> WatchList;
+
+ FileWatcherGeneric( FileWatcher * parent );
+
+ virtual ~FileWatcherGeneric();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ Thread * mThread;
+
+ /// The last watchid
+ WatchID mLastWatchID;
+
+ /// Map of WatchID to WatchStruct pointers
+ WatchList mWatches;
+
+ Mutex mWatchesLock;
+
+ bool pathInWatches( const std::string& path );
+ private:
+ void run();
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherImpl.cpp b/dep/efsw/src/efsw/FileWatcherImpl.cpp
new file mode 100644
index 00000000000..e6e0fc72a13
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherImpl.cpp
@@ -0,0 +1,29 @@
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/String.hpp>
+#include <efsw/System.hpp>
+
+namespace efsw {
+
+FileWatcherImpl::FileWatcherImpl( FileWatcher * parent ) :
+ mFileWatcher( parent ),
+ mInitOK( false ),
+ mIsGeneric( false )
+{
+ System::maxFD();
+}
+
+FileWatcherImpl::~FileWatcherImpl()
+{
+}
+
+bool FileWatcherImpl::initOK()
+{
+ return mInitOK;
+}
+
+bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link )
+{
+ return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || -1 != String::strStartsWith( curPath, link );
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileWatcherImpl.hpp b/dep/efsw/src/efsw/FileWatcherImpl.hpp
new file mode 100644
index 00000000000..8f472bf56c5
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherImpl.hpp
@@ -0,0 +1,54 @@
+#ifndef EFSW_FILEWATCHERIMPL_HPP
+#define EFSW_FILEWATCHERIMPL_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/efsw.hpp>
+#include <efsw/Watcher.hpp>
+#include <efsw/Thread.hpp>
+#include <efsw/Mutex.hpp>
+
+namespace efsw {
+
+class FileWatcherImpl
+{
+ public:
+ FileWatcherImpl( FileWatcher * parent );
+
+ virtual ~FileWatcherImpl();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ virtual WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) = 0;
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ virtual void removeWatch(const std::string& directory) = 0;
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ virtual void removeWatch(WatchID watchid) = 0;
+
+ /// Updates the watcher. Must be called often.
+ virtual void watch() = 0;
+
+ /// Handles the action
+ virtual void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "") = 0;
+
+ /// @return Returns a list of the directories that are being watched
+ virtual std::list<std::string> directories() = 0;
+
+ /// @return true if the backend init successfully
+ virtual bool initOK();
+
+ /// @return If the link is allowed according to the current path and the state of out scope links
+ virtual bool linkAllowed( const std::string& curPath, const std::string& link );
+
+ /// Search if a directory already exists in the watches
+ virtual bool pathInWatches( const std::string& path ) = 0;
+
+ FileWatcher * mFileWatcher;
+ bool mInitOK;
+ bool mIsGeneric;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherInotify.cpp b/dep/efsw/src/efsw/FileWatcherInotify.cpp
new file mode 100644
index 00000000000..19c20761663
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherInotify.cpp
@@ -0,0 +1,531 @@
+#include <efsw/FileWatcherInotify.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef EFSW_INOTIFY_NOSYS
+#include <efsw/inotify-nosys.h>
+#else
+#include <sys/inotify.h>
+#endif
+
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/Debug.hpp>
+
+#define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024)
+
+namespace efsw
+{
+
+FileWatcherInotify::FileWatcherInotify( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mFD(-1),
+ mThread(NULL)
+{
+ mFD = inotify_init();
+
+ if (mFD < 0)
+ {
+ efDEBUG( "Error: %s\n", strerror(errno) );
+ }
+ else
+ {
+ mInitOK = true;
+ }
+}
+
+FileWatcherInotify::~FileWatcherInotify()
+{
+ mInitOK = false;
+
+ efSAFE_DELETE( mThread );
+
+ WatchMap::iterator iter = mWatches.begin();
+ WatchMap::iterator end = mWatches.end();
+
+ for(; iter != end; ++iter)
+ {
+ efSAFE_DELETE( iter->second );
+ }
+
+ mWatches.clear();
+
+ if ( mFD != -1 )
+ {
+ close(mFD);
+ mFD = -1;
+ }
+}
+
+WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive )
+{
+ return addWatch( directory, watcher, recursive, NULL );
+}
+
+WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent )
+{
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+ else if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( NULL != parent && FileSystem::isRemoteFS( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, dir );
+ }
+
+ /// Check if the directory is a symbolic link
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( NULL != parent && !mFileWatcher->followSymlinks() )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ int wd = inotify_add_watch (mFD, dir.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY);
+
+ if ( wd < 0 )
+ {
+ if( errno == ENOENT )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::Unspecified, std::string(strerror(errno)) );
+ }
+ }
+
+ efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd );
+
+ WatcherInotify * pWatch = new WatcherInotify();
+ pWatch->Listener = watcher;
+ pWatch->ID = wd;
+ pWatch->Directory = dir;
+ pWatch->Recursive = recursive;
+ pWatch->Parent = parent;
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(wd, pWatch));
+ mWatchesLock.unlock();
+
+ if ( NULL == pWatch->Parent )
+ {
+ mRealWatches[ pWatch->ID ] = pWatch;
+ }
+
+ if ( pWatch->Recursive )
+ {
+ std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory );
+ std::map<std::string, FileInfo>::iterator it = files.begin();
+
+ for ( ; it != files.end(); it++ )
+ {
+ FileInfo fi = it->second;
+
+ if ( fi.isDirectory() && fi.isReadable() )
+ {
+ addWatch( fi.Filepath, watcher, recursive, pWatch );
+ }
+ }
+ }
+
+ return wd;
+}
+
+void FileWatcherInotify::removeWatchLocked(WatchID watchid)
+{
+ WatchMap::iterator iter = mWatches.find( watchid );
+
+ WatcherInotify * watch = iter->second;
+
+ if ( watch->Recursive )
+ {
+ WatchMap::iterator it = mWatches.begin();
+ std::list<WatchID> eraseWatches;
+
+ for(; it != mWatches.end(); ++it)
+ {
+ if ( it->second != watch &&
+ it->second->inParentTree( watch )
+ )
+ {
+ eraseWatches.push_back( it->second->ID );
+ }
+ }
+
+ for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ )
+ {
+ removeWatch( *eit );
+ }
+ }
+
+ mWatches.erase( iter );
+
+ if ( NULL == watch->Parent )
+ {
+ WatchMap::iterator eraseit = mRealWatches.find( watch->ID );
+
+ if ( eraseit != mRealWatches.end() )
+ {
+ mRealWatches.erase( eraseit );
+ }
+ }
+
+ int err = inotify_rm_watch(mFD, watchid);
+
+ if ( err < 0 )
+ {
+ efDEBUG( "Error removing watch %d: %s\n", watchid, strerror(errno) );
+ }
+ else
+ {
+ efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid );
+ }
+
+ efSAFE_DELETE( watch );
+}
+
+void FileWatcherInotify::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if( directory == iter->second->Directory )
+ {
+ WatcherInotify * watch = iter->second;
+
+ if ( watch->Recursive )
+ {
+ WatchMap::iterator it = mWatches.begin();
+ std::list<WatchID> eraseWatches;
+
+ for(; it != mWatches.end(); ++it)
+ {
+ if ( it->second->inParentTree( watch ) )
+ {
+ eraseWatches.push_back( it->second->ID );
+ }
+ }
+
+ for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ )
+ {
+ removeWatchLocked( *eit );
+ }
+ }
+
+ mWatches.erase( iter );
+
+ if ( NULL == watch->Parent )
+ {
+ WatchMap::iterator eraseit = mRealWatches.find( watch->ID );
+
+ if ( eraseit != mRealWatches.end() )
+ {
+ mRealWatches.erase( eraseit );
+ }
+ }
+
+ int err = inotify_rm_watch(mFD, watch->ID);
+
+ if ( err < 0 )
+ {
+ efDEBUG( "Error removing watch %d: %s\n", watch->ID, strerror(errno) );
+ }
+ else
+ {
+ efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watch->ID );
+ }
+
+ efSAFE_DELETE( watch );
+
+ break;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherInotify::removeWatch( WatchID watchid )
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.find( watchid );
+
+ if( iter == mWatches.end() )
+ {
+ mWatchesLock.unlock();
+
+ return;
+ }
+
+ removeWatchLocked( watchid );
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherInotify::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherInotify::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherInotify::run()
+{
+ static char buff[BUFF_SIZE] = {0};
+ WatchMap::iterator wit;
+ std::list<WatcherInotify*> movedOutsideWatches;
+
+ do
+ {
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET (mFD, &rfds);
+ timeval timeout;
+ timeout.tv_sec=0;
+ timeout.tv_usec=100000;
+
+ if( select (FD_SETSIZE, &rfds, NULL, NULL, &timeout) > 0 )
+ {
+ ssize_t len, i = 0;
+
+ len = read (mFD, buff, BUFF_SIZE);
+
+ if (len != -1)
+ {
+ while (i < len)
+ {
+ struct inotify_event *pevent = (struct inotify_event *)&buff[i];
+
+ mWatchesLock.lock();
+
+ wit = mWatches.find( pevent->wd );
+
+ if ( wit != mWatches.end() )
+ {
+ handleAction(wit->second, pevent->name, pevent->mask);
+
+ /// Keep track of the IN_MOVED_FROM events to known if the IN_MOVED_TO event is also fired
+ if ( !wit->second->OldFileName.empty() )
+ {
+ movedOutsideWatches.push_back( wit->second );
+ }
+ }
+
+ mWatchesLock.unlock();
+
+ i += sizeof(struct inotify_event) + pevent->len;
+ }
+
+ if ( !movedOutsideWatches.empty() )
+ {
+ /// In case that the IN_MOVED_TO is never fired means that the file was moved to other folder
+ for ( std::list<WatcherInotify*>::iterator it = movedOutsideWatches.begin(); it != movedOutsideWatches.end(); it++ )
+ {
+ if ( !(*it)->OldFileName.empty() )
+ {
+ /// So we send a IN_DELETE event for files that where moved outside of our scope
+ handleAction( *it, (*it)->OldFileName, IN_DELETE );
+
+ /// Remove the OldFileName
+ (*it)->OldFileName = "";
+ }
+ }
+
+ movedOutsideWatches.clear();
+ }
+ }
+ }
+ } while( mInitOK );
+}
+
+void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath )
+{
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher
+ if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
+ {
+ bool found = false;
+
+ /// First check if exists
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == fpath )
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ addWatch( fpath, watch->Listener, watch->Recursive, static_cast<WatcherInotify*>( watch ) );
+ }
+ }
+}
+
+void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename )
+{
+ if ( !watch || !watch->Listener )
+ {
+ return;
+ }
+
+ std::string fpath( watch->Directory + filename );
+
+ if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified );
+ }
+ else if( IN_MOVED_TO & action )
+ {
+ /// If OldFileName doesn't exist means that the file has been moved from other folder, so we just send the Add event
+ if ( watch->OldFileName.empty() )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add );
+
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified );
+
+ checkForNewWatcher( watch, fpath );
+ }
+ else
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Moved, watch->OldFileName );
+ }
+
+ if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
+ {
+ /// Update the new directory path
+ std::string opath( watch->Directory + watch->OldFileName );
+ FileSystem::dirAddSlashAtEnd( opath );
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == opath && it->second->DirInfo.Inode == FileInfo( opath ).Inode )
+ {
+ it->second->Directory = fpath;
+ it->second->DirInfo = FileInfo( fpath );
+
+ break;
+ }
+ }
+ }
+
+ watch->OldFileName = "";
+ }
+ else if( IN_CREATE & action )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add );
+
+ checkForNewWatcher( watch, fpath );
+ }
+ else if ( IN_MOVED_FROM & action )
+ {
+ watch->OldFileName = filename;
+ }
+ else if( IN_DELETE & action )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete );
+
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ /// If the file erased is a directory and recursive is enabled, removes the directory erased
+ if ( watch->Recursive )
+ {
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == fpath )
+ {
+ removeWatch( it->second->ID );
+ break;
+ }
+ }
+ }
+ }
+}
+
+std::list<std::string> FileWatcherInotify::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ WatchMap::iterator it = mRealWatches.begin();
+
+ for ( ; it != mRealWatches.end(); it++ )
+ {
+ dirs.push_back( it->second->Directory );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherInotify::pathInWatches( const std::string& path )
+{
+ /// Search in the real watches, since it must allow adding a watch already watched as a subdir
+ WatchMap::iterator it = mRealWatches.begin();
+
+ for ( ; it != mRealWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherInotify.hpp b/dep/efsw/src/efsw/FileWatcherInotify.hpp
new file mode 100644
index 00000000000..43ee9ca6afc
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherInotify.hpp
@@ -0,0 +1,73 @@
+#ifndef EFSW_FILEWATCHERLINUX_HPP
+#define EFSW_FILEWATCHERLINUX_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
+
+#include <efsw/WatcherInotify.hpp>
+#include <map>
+
+namespace efsw
+{
+
+/// Implementation for Linux based on inotify.
+/// @class FileWatcherInotify
+class FileWatcherInotify : public FileWatcherImpl
+{
+ public:
+ /// type for a map from WatchID to WatchStruct pointer
+ typedef std::map<WatchID, WatcherInotify*> WatchMap;
+
+ FileWatcherInotify( FileWatcher * parent );
+
+ virtual ~FileWatcherInotify();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ /// Map of WatchID to WatchStruct pointers
+ WatchMap mWatches;
+
+ /// User added watches
+ WatchMap mRealWatches;
+
+ /// inotify file descriptor
+ int mFD;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent = NULL );
+
+ bool pathInWatches( const std::string& path );
+ private:
+ void run();
+
+ void removeWatchLocked(WatchID watchid);
+
+ void checkForNewWatcher( Watcher* watch, std::string fpath );
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherKqueue.cpp b/dep/efsw/src/efsw/FileWatcherKqueue.cpp
new file mode 100644
index 00000000000..600fd085b35
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherKqueue.cpp
@@ -0,0 +1,274 @@
+#include <efsw/FileWatcherKqueue.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/Debug.hpp>
+#include <efsw/WatcherGeneric.hpp>
+
+namespace efsw
+{
+
+FileWatcherKqueue::FileWatcherKqueue( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mLastWatchID(0),
+ mThread( NULL ),
+ mFileDescriptorCount( 1 ),
+ mAddingWatcher( false )
+{
+ mTimeOut.tv_sec = 0;
+ mTimeOut.tv_nsec = 0;
+ mInitOK = true;
+}
+
+FileWatcherKqueue::~FileWatcherKqueue()
+{
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ efSAFE_DELETE( iter->second );
+ }
+
+ mWatches.clear();
+
+ mInitOK = false;
+
+ mThread->wait();
+
+ efSAFE_DELETE( mThread );
+}
+
+WatchID FileWatcherKqueue::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ static bool s_ug = false;
+
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+ else if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ /// Check first if are enough file descriptors available to create another kqueue watcher, otherwise it creates a generic watcher
+ if ( availablesFD() )
+ {
+ mAddingWatcher = true;
+
+ WatcherKqueue * watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this );
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ mWatchesLock.unlock();
+
+ watch->addAll();
+
+ // if failed to open the directory... erase the watcher
+ if ( !watch->initOK() )
+ {
+ int le = watch->lastErrno();
+
+ mWatches.erase( watch->ID );
+
+ efSAFE_DELETE( watch );
+
+ mLastWatchID--;
+
+ // Probably the folder has too many files, create a generic watcher
+ if ( EACCES != le )
+ {
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ mWatchesLock.unlock();
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::Unspecified, link );
+ }
+ }
+
+ mAddingWatcher = false;
+ }
+ else
+ {
+ if ( !s_ug )
+ {
+ efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", mFileDescriptorCount );
+ s_ug = true;
+ }
+
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ mWatchesLock.unlock();
+ }
+
+ return mLastWatchID;
+}
+
+void FileWatcherKqueue::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if(directory == iter->second->Directory)
+ {
+ removeWatch(iter->first);
+ return;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherKqueue::removeWatch(WatchID watchid)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.find(watchid);
+
+ if(iter == mWatches.end())
+ return;
+
+ Watcher* watch = iter->second;
+
+ mWatches.erase(iter);
+
+ efSAFE_DELETE( watch );
+
+ mWatchesLock.unlock();
+}
+
+bool FileWatcherKqueue::isAddingWatcher() const
+{
+ return mAddingWatcher;
+}
+
+void FileWatcherKqueue::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherKqueue::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherKqueue::run()
+{
+ do
+ {
+ mWatchesLock.lock();
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
+ {
+ it->second->watch();
+ }
+
+ mWatchesLock.unlock();
+
+ System::sleep( 500 );
+ } while( mInitOK );
+}
+
+void FileWatcherKqueue::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+}
+
+std::list<std::string> FileWatcherKqueue::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ WatchMap::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ dirs.push_back( it->second->Directory );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherKqueue::pathInWatches( const std::string& path )
+{
+ WatchMap::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void FileWatcherKqueue::addFD()
+{
+ mFileDescriptorCount++;
+}
+
+void FileWatcherKqueue::removeFD()
+{
+ mFileDescriptorCount--;
+}
+
+bool FileWatcherKqueue::availablesFD()
+{
+ return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherKqueue.hpp b/dep/efsw/src/efsw/FileWatcherKqueue.hpp
new file mode 100644
index 00000000000..0a2431e3777
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherKqueue.hpp
@@ -0,0 +1,78 @@
+#ifndef EFSW_FILEWATCHEROSX_HPP
+#define EFSW_FILEWATCHEROSX_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <efsw/WatcherKqueue.hpp>
+
+namespace efsw
+{
+
+/// Implementation for OSX based on kqueue.
+/// @class FileWatcherKqueue
+class FileWatcherKqueue : public FileWatcherImpl
+{
+ friend class WatcherKqueue;
+ public:
+ FileWatcherKqueue( FileWatcher * parent );
+
+ virtual ~FileWatcherKqueue();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ /// Map of WatchID to WatchStruct pointers
+ WatchMap mWatches;
+
+ /// time out data
+ struct timespec mTimeOut;
+
+ /// WatchID allocator
+ int mLastWatchID;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ std::list<WatchID> mRemoveList;
+
+ long mFileDescriptorCount;
+
+ bool mAddingWatcher;
+
+ bool isAddingWatcher() const;
+
+ bool pathInWatches( const std::string& path );
+
+ void addFD();
+
+ void removeFD();
+
+ bool availablesFD();
+ private:
+ void run();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherWin32.cpp b/dep/efsw/src/efsw/FileWatcherWin32.cpp
new file mode 100644
index 00000000000..fe78dd122cf
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherWin32.cpp
@@ -0,0 +1,291 @@
+#include <efsw/FileWatcherWin32.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw
+{
+
+FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mLastWatchID(0),
+ mThread( NULL )
+{
+ mInitOK = true;
+}
+
+FileWatcherWin32::~FileWatcherWin32()
+{
+ WatchVector::iterator iter = mWatches.begin();
+
+ mWatchesLock.lock();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ DestroyWatch((*iter));
+ }
+
+ mHandles.clear();
+ mWatches.clear();
+
+ mInitOK = false;
+
+ mWatchesLock.unlock();
+
+ efSAFE_DELETE( mThread );
+}
+
+WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ std::string dir( directory );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ WatchID watchid = ++mLastWatchID;
+
+ mWatchesLock.lock();
+
+ WatcherStructWin32 * watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), recursive, FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_SIZE
+ );
+
+ if( NULL == watch )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+
+ if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, dir );
+ }
+
+ // Add the handle to the handles vector
+ watch->Watch->ID = watchid;
+ watch->Watch->Watch = this;
+ watch->Watch->Listener = watcher;
+ watch->Watch->DirName = new char[dir.length()+1];
+ strcpy(watch->Watch->DirName, dir.c_str());
+
+ mHandles.push_back( watch->Watch->DirHandle );
+ mWatches.push_back( watch );
+ mWatchesLock.unlock();
+
+ return watchid;
+}
+
+void FileWatcherWin32::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchVector::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if(directory == (*iter)->Watch->DirName)
+ {
+ removeWatch((*iter)->Watch->ID);
+ return;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherWin32::removeWatch(WatchID watchid)
+{
+ mWatchesLock.lock();
+
+ WatchVector::iterator iter = mWatches.begin();
+
+ WatcherStructWin32* watch = NULL;
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ // Find the watch ID
+ if ( (*iter)->Watch->ID == watchid )
+ {
+ watch = (*iter);
+
+ mWatches.erase( iter );
+
+ // Remove handle from the handle vector
+ HandleVector::iterator it = mHandles.begin();
+
+ for ( ; it != mHandles.end(); it++ )
+ {
+ if ( watch->Watch->DirHandle == (*it) )
+ {
+ mHandles.erase( it );
+ break;
+ }
+ }
+
+ DestroyWatch(watch);
+
+ break;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherWin32::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherWin32::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherWin32::run()
+{
+ if ( mHandles.empty() )
+ {
+ return;
+ }
+
+ do
+ {
+ if ( !mHandles.empty() )
+ {
+ mWatchesLock.lock();
+
+ for ( std::size_t i = 0; i < mWatches.size(); i++ )
+ {
+ WatcherStructWin32 * watch = mWatches[ i ];
+
+ // If the overlapped struct was cancelled ( because the creator thread doesn't exists anymore ),
+ // we recreate the overlapped in the current thread and refresh the watch
+ if ( /*STATUS_CANCELED*/0xC0000120 == watch->Overlapped.Internal )
+ {
+ watch->Overlapped = OVERLAPPED();
+ RefreshWatch(watch);
+ }
+
+ // First ensure that the handle is the same, this means that the watch was not removed.
+ if ( HasOverlappedIoCompleted( &watch->Overlapped ) && mHandles[ i ] == watch->Watch->DirHandle )
+ {
+ DWORD bytes;
+
+ if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) )
+ {
+ WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped );
+ }
+ }
+ }
+
+ mWatchesLock.unlock();
+
+ if ( mInitOK )
+ {
+ System::sleep( 10 );
+ }
+ }
+ else
+ {
+ // Wait for a new handle to be added
+ System::sleep( 10 );
+ }
+ } while ( mInitOK );
+}
+
+void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+ Action fwAction;
+
+ switch(action)
+ {
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ watch->OldFileName = filename;
+ return;
+ case FILE_ACTION_ADDED:
+ fwAction = Actions::Add;
+ break;
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ {
+ fwAction = Actions::Moved;
+
+ std::string fpath( watch->Directory + filename );
+
+ // Update the directory path
+ if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
+ {
+ // Update the new directory path
+ std::string opath( watch->Directory + watch->OldFileName );
+ FileSystem::dirAddSlashAtEnd( opath );
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Watch->Directory == opath )
+ {
+ (*it)->Watch->Directory = fpath;
+
+ break;
+ }
+ }
+ }
+
+ watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction, watch->OldFileName);
+ return;
+ }
+ case FILE_ACTION_REMOVED:
+ fwAction = Actions::Delete;
+ break;
+ case FILE_ACTION_MODIFIED:
+ fwAction = Actions::Modified;
+ break;
+ };
+
+ watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction);
+}
+
+std::list<std::string> FileWatcherWin32::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ dirs.push_back( std::string( (*it)->Watch->DirName ) );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherWin32::pathInWatches( const std::string& path )
+{
+ for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Watch->DirName == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherWin32.hpp b/dep/efsw/src/efsw/FileWatcherWin32.hpp
new file mode 100644
index 00000000000..505cd772b82
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherWin32.hpp
@@ -0,0 +1,69 @@
+#ifndef EFSW_FILEWATCHERWIN32_HPP
+#define EFSW_FILEWATCHERWIN32_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#include <efsw/WatcherWin32.hpp>
+#include <vector>
+#include <map>
+
+namespace efsw
+{
+
+/// Implementation for Win32 based on ReadDirectoryChangesW.
+/// @class FileWatcherWin32
+class FileWatcherWin32 : public FileWatcherImpl
+{
+ public:
+ /// type for a map from WatchID to WatcherWin32 pointer
+ typedef std::vector<WatcherStructWin32*> WatchVector;
+ typedef std::vector<HANDLE> HandleVector;
+
+ FileWatcherWin32( FileWatcher * parent );
+
+ virtual ~FileWatcherWin32();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ /// Vector of WatcherWin32 pointers
+ WatchVector mWatches;
+
+ /// Keeps an updated handles vector
+ HandleVector mHandles;
+
+ /// The last watchid
+ WatchID mLastWatchID;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ bool pathInWatches( const std::string& path );
+ private:
+ void run();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/Log.cpp b/dep/efsw/src/efsw/Log.cpp
new file mode 100644
index 00000000000..8e2860ac099
--- /dev/null
+++ b/dep/efsw/src/efsw/Log.cpp
@@ -0,0 +1,27 @@
+#include <efsw/efsw.hpp>
+
+namespace efsw { namespace Errors {
+
+static std::string LastError;
+
+std::string Log::getLastErrorLog()
+{
+ return LastError;
+}
+
+Error Log::createLastError( Error err, std::string log )
+{
+ switch ( err )
+ {
+ case FileNotFound: LastError = "File not found ( " + log + " )"; break;
+ case FileRepeated: LastError = "File reapeated in watches ( " + log + " )"; break;
+ case FileOutOfScope: LastError = "Symlink file out of scope ( " + log + " )"; break;
+ case FileRemote: LastError = "File is located in a remote file system, use a generic watcher. ( " + log + " )"; break;
+ case Unspecified:
+ default: LastError = log;
+ }
+
+ return err;
+}
+
+}}
diff --git a/dep/efsw/src/efsw/Mutex.cpp b/dep/efsw/src/efsw/Mutex.cpp
new file mode 100644
index 00000000000..b34ba066ee9
--- /dev/null
+++ b/dep/efsw/src/efsw/Mutex.cpp
@@ -0,0 +1,26 @@
+#include <efsw/Mutex.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+namespace efsw {
+
+Mutex::Mutex() :
+ mMutexImpl( new Platform::MutexImpl() )
+{
+}
+
+Mutex::~Mutex()
+{
+ efSAFE_DELETE( mMutexImpl );
+}
+
+void Mutex::lock()
+{
+ mMutexImpl->lock();
+}
+
+void Mutex::unlock()
+{
+ mMutexImpl->unlock();
+}
+
+}
diff --git a/dep/efsw/src/efsw/Mutex.hpp b/dep/efsw/src/efsw/Mutex.hpp
new file mode 100644
index 00000000000..e6e89def175
--- /dev/null
+++ b/dep/efsw/src/efsw/Mutex.hpp
@@ -0,0 +1,28 @@
+#ifndef EFSW_MUTEX_HPP
+#define EFSW_MUTEX_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+namespace Platform { class MutexImpl; }
+
+/** Simple mutex class */
+class Mutex {
+ public:
+ Mutex();
+
+ ~Mutex();
+
+ /** Lock the mutex */
+ void lock();
+
+ /** Unlock the mutex */
+ void unlock();
+ private:
+ Platform::MutexImpl * mMutexImpl;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/String.cpp b/dep/efsw/src/efsw/String.cpp
new file mode 100644
index 00000000000..f703d25cb35
--- /dev/null
+++ b/dep/efsw/src/efsw/String.cpp
@@ -0,0 +1,813 @@
+#include <iterator>
+#include <efsw/String.hpp>
+#include <efsw/Utf.hpp>
+
+namespace efsw {
+
+const std::size_t String::InvalidPos = StringType::npos;
+
+std::vector < std::string > String::split ( const std::string& str, const char& splitchar, const bool& pushEmptyString )
+{
+ std::vector < std::string > tmp;
+ std::string tmpstr;
+
+ for ( size_t i = 0; i < str.size(); i++ )
+ {
+ if ( str[i] == splitchar )
+ {
+ if ( pushEmptyString || tmpstr.size() )
+ {
+ tmp.push_back(tmpstr);
+ tmpstr = "";
+ }
+ }
+ else
+ {
+ tmpstr += str[i];
+ }
+ }
+
+ if ( tmpstr.size() )
+ {
+ tmp.push_back( tmpstr );
+ }
+
+ return tmp;
+}
+
+std::vector < String > String::split ( const String& str, const Uint32& splitchar, const bool& pushEmptyString )
+{
+ std::vector < String > tmp;
+ String tmpstr;
+
+ for ( size_t i = 0; i < str.size(); i++ )
+ {
+ if ( str[i] == splitchar )
+ {
+ if ( pushEmptyString || tmpstr.size() )
+ {
+ tmp.push_back(tmpstr);
+ tmpstr = "";
+ }
+ }
+ else
+ {
+ tmpstr += str[i];
+ }
+ }
+
+ if ( tmpstr.size() )
+ {
+ tmp.push_back( tmpstr );
+ }
+
+ return tmp;
+}
+
+int String::strStartsWith( const std::string& start, const std::string& str )
+{
+ int pos = -1;
+ size_t size = start.size();
+
+ if ( str.size() >= size )
+ {
+ for ( std::size_t i = 0; i < size; i++ )
+ {
+ if ( start[i] == str[i] )
+ {
+ pos = (int)i;
+ }
+ else
+ {
+ pos = -1;
+ break;
+ }
+ }
+ }
+
+ return pos;
+}
+
+int String::strStartsWith( const String& start, const String& str )
+{
+ int pos = -1;
+ size_t size = start.size();
+
+ if ( str.size() >= size )
+ {
+ for ( std::size_t i = 0; i < size; i++ )
+ {
+ if ( start[i] == str[i] )
+ {
+ pos = (int)i;
+ }
+ else
+ {
+ pos = -1;
+ break;
+ }
+ }
+ }
+
+ return pos;
+}
+
+String::String()
+{
+}
+
+String::String(char ansiChar, const std::locale& locale)
+{
+ mString += Utf32::DecodeAnsi(ansiChar, locale);
+}
+
+#ifndef EFSW_NO_WIDECHAR
+String::String(wchar_t wideChar)
+{
+ mString += Utf32::DecodeWide(wideChar);
+}
+#endif
+
+String::String(StringBaseType utf32Char)
+{
+ mString += utf32Char;
+}
+
+String::String( const char* uf8String ) {
+ if (uf8String)
+ {
+ std::size_t length = strlen(uf8String);
+
+ if (length > 0)
+ {
+ mString.reserve(length + 1);
+
+ Utf8::ToUtf32(uf8String, uf8String + length, std::back_inserter(mString));
+ }
+ }
+}
+
+String::String( const std::string& utf8String ) {
+ mString.reserve( utf8String.length() + 1 );
+
+ Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( mString ) );
+}
+
+String::String(const char* ansiString, const std::locale& locale)
+{
+ if (ansiString)
+ {
+ std::size_t length = strlen(ansiString);
+ if (length > 0)
+ {
+ mString.reserve(length + 1);
+ Utf32::FromAnsi(ansiString, ansiString + length, std::back_inserter(mString), locale);
+ }
+ }
+}
+
+String::String(const std::string& ansiString, const std::locale& locale)
+{
+ mString.reserve(ansiString.length() + 1);
+ Utf32::FromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(mString), locale);
+}
+
+#ifndef EFSW_NO_WIDECHAR
+String::String(const wchar_t* wideString)
+{
+ if (wideString)
+ {
+ std::size_t length = std::wcslen(wideString);
+ if (length > 0)
+ {
+ mString.reserve(length + 1);
+ Utf32::FromWide(wideString, wideString + length, std::back_inserter(mString));
+ }
+ }
+}
+
+String::String(const std::wstring& wideString)
+{
+ mString.reserve(wideString.length() + 1);
+ Utf32::FromWide(wideString.begin(), wideString.end(), std::back_inserter(mString));
+}
+#endif
+
+String::String(const StringBaseType* utf32String)
+{
+ if (utf32String)
+ mString = utf32String;
+}
+
+String::String(const StringType& utf32String) :
+mString(utf32String)
+{
+}
+
+String::String(const String& str) :
+mString(str.mString)
+{
+}
+
+String String::fromUtf8( const std::string& utf8String )
+{
+ String::StringType utf32;
+
+ utf32.reserve( utf8String.length() + 1 );
+
+ Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( utf32 ) );
+
+ return String( utf32 );
+}
+
+String::operator std::string() const
+{
+ return toAnsiString();
+}
+
+std::string String::toAnsiString(const std::locale& locale) const
+{
+ // Prepare the output string
+ std::string output;
+ output.reserve(mString.length() + 1);
+
+ // Convert
+ Utf32::ToAnsi(mString.begin(), mString.end(), std::back_inserter(output), 0, locale);
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+std::wstring String::toWideString() const
+{
+ // Prepare the output string
+ std::wstring output;
+ output.reserve(mString.length() + 1);
+
+ // Convert
+ Utf32::ToWide(mString.begin(), mString.end(), std::back_inserter(output), 0);
+
+ return output;
+}
+#endif
+
+std::string String::toUtf8() const {
+ // Prepare the output string
+ std::string output;
+ output.reserve(mString.length() + 1);
+
+ // Convert
+ Utf32::toUtf8(mString.begin(), mString.end(), std::back_inserter(output) );
+
+ return output;
+}
+
+String& String::operator =(const String& right)
+{
+ mString = right.mString;
+ return *this;
+}
+
+String& String::operator =( const StringBaseType& right )
+{
+ mString = right;
+ return *this;
+}
+
+String& String::operator +=(const String& right)
+{
+ mString += right.mString;
+ return *this;
+}
+
+String& String::operator +=( const StringBaseType& right )
+{
+ mString += right;
+ return *this;
+}
+
+
+String::StringBaseType String::operator [](std::size_t index) const
+{
+ return mString[index];
+}
+
+String::StringBaseType& String::operator [](std::size_t index)
+{
+ return mString[index];
+}
+
+String::StringBaseType String::at( std::size_t index ) const
+{
+ return mString.at( index );
+}
+
+void String::push_back( StringBaseType c )
+{
+ mString.push_back( c );
+}
+
+void String::swap ( String& str )
+{
+ mString.swap( str.mString );
+}
+
+void String::clear()
+{
+ mString.clear();
+}
+
+std::size_t String::size() const
+{
+ return mString.size();
+}
+
+std::size_t String::length() const
+{
+ return mString.length();
+}
+
+bool String::empty() const
+{
+ return mString.empty();
+}
+
+void String::erase(std::size_t position, std::size_t count)
+{
+ mString.erase(position, count);
+}
+
+String& String::insert(std::size_t position, const String& str)
+{
+ mString.insert(position, str.mString);
+ return *this;
+}
+
+String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n )
+{
+ mString.insert( pos1, str.mString, pos2, n );
+ return *this;
+}
+
+String& String::insert ( size_t pos1, const char* s, size_t n )
+{
+ String tmp( s );
+
+ mString.insert( pos1, tmp.data(), n );
+
+ return *this;
+}
+
+String& String::insert ( size_t pos1, size_t n, char c )
+{
+ mString.insert( pos1, n, c );
+ return *this;
+}
+
+String& String::insert ( size_t pos1, const char* s )
+{
+ String tmp( s );
+
+ mString.insert( pos1, tmp.data() );
+
+ return *this;
+}
+
+String::Iterator String::insert ( Iterator p, char c )
+{
+ return mString.insert( p, c );
+}
+
+void String::insert ( Iterator p, size_t n, char c )
+{
+ mString.insert( p, n, c );
+}
+
+const String::StringBaseType* String::c_str() const
+{
+ return mString.c_str();
+}
+
+const String::StringBaseType* String::data() const
+{
+ return mString.data();
+}
+
+String::Iterator String::begin()
+{
+ return mString.begin();
+}
+
+String::ConstIterator String::begin() const
+{
+ return mString.begin();
+}
+
+String::Iterator String::end()
+{
+ return mString.end();
+}
+
+String::ConstIterator String::end() const
+{
+ return mString.end();
+}
+
+String::ReverseIterator String::rbegin()
+{
+ return mString.rbegin();
+}
+
+String::ConstReverseIterator String::rbegin() const
+{
+ return mString.rbegin();
+}
+
+String::ReverseIterator String::rend()
+{
+ return mString.rend();
+}
+
+String::ConstReverseIterator String::rend() const
+{
+ return mString.rend();
+}
+
+void String::resize( std::size_t n, StringBaseType c )
+{
+ mString.resize( n, c );
+}
+
+void String::resize( std::size_t n )
+{
+ mString.resize( n );
+}
+
+std::size_t String::max_size() const
+{
+ return mString.max_size();
+}
+
+void String::reserve( size_t res_arg )
+{
+ mString.reserve( res_arg );
+}
+
+std::size_t String::capacity() const
+{
+ return mString.capacity();
+}
+
+String& String::assign ( const String& str )
+{
+ mString.assign( str.mString );
+ return *this;
+}
+
+String& String::assign ( const String& str, size_t pos, size_t n )
+{
+ mString.assign( str.mString, pos, n );
+ return *this;
+}
+
+String& String::assign ( const char* s, size_t n )
+{
+ String tmp( s );
+
+ mString.assign( tmp.mString );
+
+ return *this;
+}
+
+String& String::assign ( const char* s )
+{
+ String tmp( s );
+
+ mString.assign( tmp.mString );
+
+ return *this;
+}
+
+String& String::assign ( size_t n, char c )
+{
+ mString.assign( n, c );
+
+ return *this;
+}
+
+String& String::append ( const String& str )
+{
+ mString.append( str.mString );
+
+ return *this;
+}
+
+String& String::append ( const String& str, size_t pos, size_t n )
+{
+ mString.append( str.mString, pos, n );
+
+ return *this;
+}
+
+String& String::append ( const char* s, size_t n )
+{
+ String tmp( s );
+
+ mString.append( tmp.mString );
+
+ return *this;
+}
+
+String& String::append ( const char* s )
+{
+ String tmp( s );
+
+ mString.append( tmp.mString );
+
+ return *this;
+}
+
+String& String::append ( size_t n, char c )
+{
+ mString.append( n, c );
+
+ return *this;
+}
+
+String& String::append ( std::size_t n, StringBaseType c )
+{
+ mString.append( n, c );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const String& str )
+{
+ mString.replace( pos1, n1, str.mString );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, const String& str )
+{
+ mString.replace( i1, i2, str.mString );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 )
+{
+ mString.replace( pos1, n1, str.mString, pos2, n2 );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const char* s, size_t n2 )
+{
+ String tmp( s );
+
+ mString.replace( pos1, n1, tmp.data(), n2 );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, const char* s, size_t n2 )
+{
+ String tmp( s );
+
+ mString.replace( i1, i2, tmp.data(), n2 );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const char* s )
+{
+ String tmp( s );
+
+ mString.replace( pos1, n1, tmp.mString );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, const char* s )
+{
+ String tmp( s );
+
+ mString.replace( i1, i2, tmp.mString );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, size_t n2, char c )
+{
+ mString.replace( pos1, n1, n2, (StringBaseType)c );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, size_t n2, char c )
+{
+ mString.replace( i1, i2, n2, (StringBaseType)c );
+
+ return *this;
+}
+
+std::size_t String::find( const String& str, std::size_t start ) const
+{
+ return mString.find( str.mString, start );
+}
+
+std::size_t String::find ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find( String( s ), pos );
+}
+
+std::size_t String::find ( const char* s, std::size_t pos ) const
+{
+ return find( String( s ), pos );
+}
+
+size_t String::find ( char c, std::size_t pos ) const
+{
+ return mString.find( (StringBaseType)c, pos );
+}
+
+std::size_t String::rfind ( const String& str, std::size_t pos ) const
+{
+ return mString.rfind( str.mString, pos );
+}
+
+std::size_t String::rfind ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return rfind( String( s ), pos );
+}
+
+std::size_t String::rfind ( const char* s, std::size_t pos ) const
+{
+ return rfind( String( s ), pos );
+}
+
+std::size_t String::rfind ( char c, std::size_t pos ) const
+{
+ return mString.rfind( c, pos );
+}
+
+std::size_t String::copy ( StringBaseType* s, std::size_t n, std::size_t pos ) const
+{
+ return mString.copy( s, n, pos );
+}
+
+String String::substr ( std::size_t pos, std::size_t n ) const
+{
+ return String( mString.substr( pos, n ) );
+}
+
+int String::compare ( const String& str ) const
+{
+ return mString.compare( str.mString );
+}
+
+int String::compare ( const char* s ) const
+{
+ return compare( String( s ) );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const String& str ) const
+{
+ return mString.compare( pos1, n1, str.mString );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const char* s) const
+{
+ return compare( pos1, n1, String( s ) );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const
+{
+ return mString.compare( pos1, n1, str.mString, pos2, n2 );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const
+{
+ return compare( pos1, n1, String( s ), 0, n2 );
+}
+
+std::size_t String::find_first_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_first_of( str.mString, pos );
+}
+
+std::size_t String::find_first_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_first_of( String( s ), pos );
+}
+
+std::size_t String::find_first_of ( const char* s, std::size_t pos ) const
+{
+ return find_first_of( String( s ), pos );
+}
+
+std::size_t String::find_first_of ( StringBaseType c, std::size_t pos ) const
+{
+ return mString.find_first_of( c, pos );
+}
+
+std::size_t String::find_last_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_last_of( str.mString, pos );
+}
+
+std::size_t String::find_last_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_last_of( String( s ), pos );
+}
+
+std::size_t String::find_last_of ( const char* s, std::size_t pos ) const
+{
+ return find_last_of( String( s ), pos );
+}
+
+std::size_t String::find_last_of ( StringBaseType c, std::size_t pos) const
+{
+ return mString.find_last_of( c, pos );
+}
+
+std::size_t String::find_first_not_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_first_not_of( str.mString, pos );
+}
+
+std::size_t String::find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_first_not_of( String( s ), pos );
+}
+
+std::size_t String::find_first_not_of ( const char* s, std::size_t pos ) const
+{
+ return find_first_not_of( String( s ), pos );
+}
+
+std::size_t String::find_first_not_of ( StringBaseType c, std::size_t pos ) const
+{
+ return mString.find_first_not_of( c, pos );
+}
+
+std::size_t String::find_last_not_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_last_not_of( str.mString, pos );
+}
+
+std::size_t String::find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_last_not_of( String( s ), pos );
+}
+
+std::size_t String::find_last_not_of ( const char* s, std::size_t pos ) const
+{
+ return find_last_not_of( String( s ), pos );
+}
+
+std::size_t String::find_last_not_of ( StringBaseType c, std::size_t pos ) const
+{
+ return mString.find_last_not_of( c, pos );
+}
+
+bool operator ==(const String& left, const String& right)
+{
+ return left.mString == right.mString;
+}
+
+bool operator !=(const String& left, const String& right)
+{
+ return !(left == right);
+}
+
+bool operator <(const String& left, const String& right)
+{
+ return left.mString < right.mString;
+}
+
+bool operator >(const String& left, const String& right)
+{
+ return right < left;
+}
+
+bool operator <=(const String& left, const String& right)
+{
+ return !(right < left);
+}
+
+bool operator >=(const String& left, const String& right)
+{
+ return !(left < right);
+}
+
+String operator +(const String& left, const String& right)
+{
+ String string = left;
+ string += right;
+
+ return string;
+}
+
+}
diff --git a/dep/efsw/src/efsw/String.hpp b/dep/efsw/src/efsw/String.hpp
new file mode 100644
index 00000000000..ce7e3b75f89
--- /dev/null
+++ b/dep/efsw/src/efsw/String.hpp
@@ -0,0 +1,629 @@
+/** NOTE:
+* This code is based on the Utf implementation from SFML2. License zlib/png ( http://www.sfml-dev.org/license.php )
+* The class was modified to fit efsw own needs. This is not the original implementation from SFML2.
+* Functions and methods are the same that in std::string to facilitate portability.
+**/
+
+#ifndef EFSW_STRING_HPP
+#define EFSW_STRING_HPP
+
+#include <efsw/base.hpp>
+#include <locale>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+
+namespace efsw {
+
+/** @brief Utility string class that automatically handles conversions between types and encodings **/
+class String
+{
+ public :
+ typedef Uint32 StringBaseType;
+ typedef std::basic_string<StringBaseType> StringType;
+ typedef StringType::iterator Iterator; //! Iterator type
+ typedef StringType::const_iterator ConstIterator; //! Constant iterator type
+ typedef StringType::reverse_iterator ReverseIterator; //! Reverse Iterator type
+ typedef StringType::const_reverse_iterator ConstReverseIterator; //! Constant iterator type
+
+ static const std::size_t InvalidPos; ///< Represents an invalid position in the string
+
+ template <class T>
+ static std::string toStr(const T& i) {
+ std::ostringstream ss;
+ ss << i;
+ return ss.str();
+ }
+
+ /** Converts from a string to type */
+ template <class T>
+ static bool fromString(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) {
+ std::istringstream iss(s);
+ return !(iss >> f >> t).fail();
+ }
+
+ /** Converts from a String to type */
+ template <class T>
+ static bool fromString(T& t, const String& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) {
+ std::istringstream iss( s.toUtf8() );
+ return !(iss >> f >> t).fail();
+ }
+
+ /** Split a string and hold it on a vector */
+ static std::vector < std::string > split( const std::string& str, const char& splitchar, const bool& pushEmptyString = false );
+
+ /** Split a string and hold it on a vector */
+ static std::vector < String > split( const String& str, const Uint32& splitchar, const bool& pushEmptyString = false );
+
+ /** Determine if a string starts with the string passed
+ ** @param start The substring expected to start
+ ** @param str The string to compare
+ ** @return -1 if the substring is no in str, otherwise the size of the substring
+ */
+ static int strStartsWith( const std::string& start, const std::string& str );
+
+ static int strStartsWith( const String& start, const String& str );
+
+ /** @brief Construct from an UTF-8 string to UTF-32 according
+ ** @param uf8String UTF-8 string to convert
+ **/
+ static String fromUtf8( const std::string& utf8String );
+
+ /** @brief Default constructor
+ ** This constructor creates an empty string.
+ **/
+ String();
+
+ /** @brief Construct from a single ANSI character and a locale
+ ** The source character is converted to UTF-32 according
+ ** to the given locale. If you want to use the current global
+ ** locale, rather use the other constructor.
+ ** @param ansiChar ANSI character to convert
+ ** @param locale Locale to use for conversion
+ **/
+ String( char ansiChar, const std::locale& locale = std::locale() );
+
+#ifndef EFSW_NO_WIDECHAR
+ /** @brief Construct from single wide character
+ ** @param wideChar Wide character to convert
+ **/
+ String( wchar_t wideChar );
+#endif
+
+ /** @brief Construct from single UTF-32 character
+ ** @param utf32Char UTF-32 character to convert
+ **/
+ String( StringBaseType utf32Char );
+
+ /** @brief Construct from an from a null-terminated C-style UTF-8 string to UTF-32
+ ** @param uf8String UTF-8 string to convert
+ **/
+ String( const char* uf8String );
+
+ /** @brief Construct from an UTF-8 string to UTF-32 according
+ ** @param uf8String UTF-8 string to convert
+ **/
+ String( const std::string& utf8String );
+
+ /** @brief Construct from a null-terminated C-style ANSI string and a locale
+ ** The source string is converted to UTF-32 according
+ ** to the given locale. If you want to use the current global
+ ** locale, rather use the other constructor.
+ ** @param ansiString ANSI string to convert
+ ** @param locale Locale to use for conversion
+ **/
+ String( const char* ansiString, const std::locale& locale );
+
+ /** @brief Construct from an ANSI string and a locale
+ ** The source string is converted to UTF-32 according
+ ** to the given locale. If you want to use the current global
+ ** locale, rather use the other constructor.
+ ** @param ansiString ANSI string to convert
+ ** @param locale Locale to use for conversion
+ **/
+ String( const std::string& ansiString, const std::locale& locale );
+
+#ifndef EFSW_NO_WIDECHAR
+ /** @brief Construct from null-terminated C-style wide string
+ ** @param wideString Wide string to convert
+ **/
+ String( const wchar_t* wideString );
+
+ /** @brief Construct from a wide string
+ ** @param wideString Wide string to convert
+ **/
+ String( const std::wstring& wideString );
+#endif
+
+ /** @brief Construct from a null-terminated C-style UTF-32 string
+ ** @param utf32String UTF-32 string to assign
+ **/
+ String( const StringBaseType* utf32String );
+
+ /** @brief Construct from an UTF-32 string
+ ** @param utf32String UTF-32 string to assign
+ **/
+ String( const StringType& utf32String );
+
+
+ /** @brief Copy constructor
+ ** @param str Instance to copy
+ **/
+ String( const String& str );
+
+ /** @brief Implicit cast operator to std::string (ANSI string)
+ ** The current global locale is used for conversion. If you
+ ** want to explicitely specify a locale, see toAnsiString.
+ ** Characters that do not fit in the target encoding are
+ ** discarded from the returned string.
+ ** This operator is defined for convenience, and is equivalent
+ ** to calling toAnsiString().
+ ** @return Converted ANSI string
+ ** @see toAnsiString, operator String
+ **/
+ operator std::string() const;
+
+ /** @brief Convert the unicode string to an ANSI string
+ ** The UTF-32 string is converted to an ANSI string in
+ ** the encoding defined by \a locale. If you want to use
+ ** the current global locale, see the other overload
+ ** of toAnsiString.
+ ** Characters that do not fit in the target encoding are
+ ** discarded from the returned string.
+ ** @param locale Locale to use for conversion
+ ** @return Converted ANSI string
+ ** @see toWideString, operator std::string
+ **/
+ std::string toAnsiString( const std::locale& locale = std::locale() ) const;
+
+#ifndef EFSW_NO_WIDECHAR
+ /** @brief Convert the unicode string to a wide string
+ ** Characters that do not fit in the target encoding are
+ ** discarded from the returned string.
+ ** @return Converted wide string
+ ** @see toAnsiString, operator String
+ **/
+ std::wstring toWideString() const;
+#endif
+
+ std::string toUtf8() const;
+
+ /** @brief Overload of assignment operator
+ ** @param right Instance to assign
+ ** @return Reference to self
+ **/
+ String& operator =(const String& right);
+
+ String& operator =( const StringBaseType& right );
+
+ /** @brief Overload of += operator to append an UTF-32 string
+ ** @param right String to append
+ ** @return Reference to self
+ **/
+ String& operator +=(const String& right);
+
+ String& operator +=( const StringBaseType& right );
+
+ /** @brief Overload of [] operator to access a character by its position
+ ** This function provides read-only access to characters.
+ ** Note: this function doesn't throw if \a index is out of range.
+ ** @param index Index of the character to get
+ ** @return Character at position \a index
+ **/
+ StringBaseType operator [](std::size_t index) const;
+
+ /** @brief Overload of [] operator to access a character by its position
+ ** This function provides read and write access to characters.
+ ** Note: this function doesn't throw if \a index is out of range.
+ ** @param index Index of the character to get
+ ** @return Reference to the character at position \a index
+ **/
+
+ StringBaseType& operator [](std::size_t index);
+
+ /** @brief Get character in string
+ ** Performs a range check, throwing an exception of type out_of_range in case that pos is not an actual position in the string.
+ ** @return The character at position pos in the string.
+ */
+ StringBaseType at( std::size_t index ) const;
+
+ /** @brief clear the string
+ ** This function removes all the characters from the string.
+ ** @see empty, erase
+ **/
+ void clear();
+
+ /** @brief Get the size of the string
+ ** @return Number of characters in the string
+ ** @see empty
+ **/
+ std::size_t size() const;
+
+ /** @see size() */
+ std::size_t length() const;
+
+ /** @brief Check whether the string is empty or not
+ ** @return True if the string is empty (i.e. contains no character)
+ ** @see clear, size
+ **/
+ bool empty() const;
+
+ /** @brief Erase one or more characters from the string
+ ** This function removes a sequence of \a count characters
+ ** starting from \a position.
+ ** @param position Position of the first character to erase
+ ** @param count Number of characters to erase
+ **/
+ void erase(std::size_t position, std::size_t count = 1);
+
+
+ /** @brief Insert one or more characters into the string
+ ** This function inserts the characters of \a str
+ ** into the string, starting from \a position.
+ ** @param position Position of insertion
+ ** @param str Characters to insert
+ **/
+ String& insert(std::size_t position, const String& str);
+
+ String& insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n );
+
+ String& insert ( std::size_t pos1, const char* s, std::size_t n );
+
+ String& insert ( std::size_t pos1, const char* s );
+
+ String& insert ( std::size_t pos1, size_t n, char c );
+
+ Iterator insert ( Iterator p, char c );
+
+ void insert ( Iterator p, std::size_t n, char c );
+
+ template<class InputIterator>
+ void insert ( Iterator p, InputIterator first, InputIterator last )
+ {
+ mString.insert( p, first, last );
+ }
+
+ /** @brief Find a sequence of one or more characters in the string
+ ** This function searches for the characters of \a str
+ ** into the string, starting from \a start.
+ ** @param str Characters to find
+ ** @param start Where to begin searching
+ ** @return Position of \a str in the string, or String::InvalidPos if not found
+ **/
+ std::size_t find( const String& str, std::size_t start = 0 ) const;
+
+ std::size_t find ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find ( const char* s, std::size_t pos = 0 ) const;
+
+ std::size_t find ( char c, std::size_t pos = 0 ) const;
+
+ /** @brief Get a pointer to the C-style array of characters
+ ** This functions provides a read-only access to a
+ ** null-terminated C-style representation of the string.
+ ** The returned pointer is temporary and is meant only for
+ ** immediate use, thus it is not recommended to store it.
+ ** @return Read-only pointer to the array of characters
+ **/
+ const StringBaseType* c_str() const;
+
+ /** @brief Get string data
+ ** Notice that no terminating null character is appended (see member c_str for such a functionality).
+ ** The returned array points to an internal location which should not be modified directly in the program.
+ ** Its contents are guaranteed to remain unchanged only until the next call to a non-constant member function of the string object.
+ ** @return Pointer to an internal array containing the same content as the string.
+ **/
+ const StringBaseType* data() const;
+
+ /** @brief Return an iterator to the beginning of the string
+ ** @return Read-write iterator to the beginning of the string characters
+ ** @see end
+ **/
+ Iterator begin();
+
+ /** @brief Return an iterator to the beginning of the string
+ ** @return Read-only iterator to the beginning of the string characters
+ ** @see end
+ **/
+ ConstIterator begin() const;
+
+ /** @brief Return an iterator to the beginning of the string
+ ** The end iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-write iterator to the end of the string characters
+ ** @see begin
+ **/
+ Iterator end();
+
+ /** @brief Return an iterator to the beginning of the string
+ ** The end iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-only iterator to the end of the string characters
+ ** @see begin
+ **/
+ ConstIterator end() const;
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** @return Read-write reverse iterator to the beginning of the string characters
+ ** @see end
+ **/
+ ReverseIterator rbegin();
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** @return Read-only reverse iterator to the beginning of the string characters
+ ** @see end
+ **/
+ ConstReverseIterator rbegin() const;
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** The end reverse iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-write reverse iterator to the end of the string characters
+ ** @see begin
+ **/
+ ReverseIterator rend();
+
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** The end reverse iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-only reverse iterator to the end of the string characters
+ ** @see begin
+ **/
+ ConstReverseIterator rend() const;
+
+ /** @brief Resize String */
+ void resize ( std::size_t n, StringBaseType c );
+
+ /** @brief Resize String */
+ void resize ( std::size_t n );
+
+ /** @return Maximum size of string */
+ std::size_t max_size() const;
+
+ /** @brief Request a change in capacity */
+ void reserve ( size_t res_arg=0 );
+
+ /** @return Size of allocated storage */
+ std::size_t capacity() const;
+
+ /** @brief Append character to string */
+ void push_back( StringBaseType c );
+
+ /** @brief Swap contents with another string */
+ void swap ( String& str );
+
+ String& assign ( const String& str );
+
+ String& assign ( const String& str, std::size_t pos, std::size_t n );
+
+ String& assign ( const char* s, std::size_t n );
+
+ String& assign ( const char* s );
+
+ String& assign ( std::size_t n, char c );
+
+ template <class InputIterator>
+ String& assign ( InputIterator first, InputIterator last )
+ {
+ mString.assign( first, last );
+ return *this;
+ }
+
+ String& append ( const String& str );
+
+ String& append ( const String& str, std::size_t pos, std::size_t n );
+
+ String& append ( const char* s, std::size_t n );
+
+ String& append ( const char* s );
+
+ String& append ( std::size_t n, char c );
+
+ String& append ( std::size_t n, StringBaseType c );
+
+ template <class InputIterator>
+ String& append ( InputIterator first, InputIterator last )
+ {
+ mString.append( first, last );
+ return *this;
+ }
+
+ String& replace ( std::size_t pos1, std::size_t n1, const String& str );
+
+ String& replace ( Iterator i1, Iterator i2, const String& str );
+
+ String& replace ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 );
+
+ String& replace ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 );
+
+ String& replace ( Iterator i1, Iterator i2, const char* s, std::size_t n2 );
+
+ String& replace ( std::size_t pos1, std::size_t n1, const char* s );
+
+ String& replace ( Iterator i1, Iterator i2, const char* s );
+
+ String& replace ( std::size_t pos1, std::size_t n1, std::size_t n2, char c );
+
+ String& replace ( Iterator i1, Iterator i2, std::size_t n2, char c );
+
+ template<class InputIterator>
+ String& replace ( Iterator i1, Iterator i2, InputIterator j1, InputIterator j2 )
+ {
+ mString.replace( i1, i2, j1, j2 );
+ return *this;
+ }
+
+ std::size_t rfind ( const String& str, std::size_t pos = StringType::npos ) const;
+
+ std::size_t rfind ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t rfind ( const char* s, std::size_t pos = StringType::npos ) const;
+
+ std::size_t rfind ( char c, std::size_t pos = StringType::npos ) const;
+
+ String substr ( std::size_t pos = 0, std::size_t n = StringType::npos ) const;
+
+ std::size_t copy ( StringBaseType* s, std::size_t n, std::size_t pos = 0 ) const;
+
+ int compare ( const String& str ) const;
+
+ int compare ( const char* s ) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const String& str ) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const char* s) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const;
+
+ std::size_t find_first_of ( const String& str, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_first_of ( const char* s, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_of ( StringBaseType c, std::size_t pos = 0 ) const;
+
+ std::size_t find_last_of ( const String& str, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_last_of ( const char* s, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_of ( StringBaseType c, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_first_not_of ( const String& str, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_first_not_of ( const char* s, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_not_of ( StringBaseType c, std::size_t pos = 0 ) const;
+
+ std::size_t find_last_not_of ( const String& str, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_last_not_of ( const char* s, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_not_of ( StringBaseType c, std::size_t pos = StringType::npos ) const;
+private :
+ friend bool operator ==(const String& left, const String& right);
+ friend bool operator <(const String& left, const String& right);
+
+ StringType mString; ///< Internal string of UTF-32 characters
+};
+
+/** @relates String
+** @brief Overload of == operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if both strings are equal
+**/
+ bool operator ==(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of != operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if both strings are different
+**/
+ bool operator !=(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of < operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically lesser than \a right
+**/
+ bool operator <(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of > operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically greater than \a right
+**/
+ bool operator >(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of <= operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically lesser or equal than \a right
+**/
+ bool operator <=(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of >= operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically greater or equal than \a right
+**/
+ bool operator >=(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of binary + operator to concatenate two strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return Concatenated string
+**/
+ String operator +( const String& left, const String& right );
+
+}
+
+#endif
+
+/** @class efsw::String
+** @ingroup system
+** efsw::String is a utility string class defined mainly for
+** convenience. It is a Unicode string (implemented using
+** UTF-32), thus it can store any character in the world
+** (european, chinese, arabic, hebrew, etc.).
+** It automatically handles conversions from/to ANSI and
+** wide strings, so that you can work with standard string
+** classes and still be compatible with functions taking a
+** efsw::String.
+** @code
+** efsw::String s;
+** std::string s1 = s; // automatically converted to ANSI string
+** String s2 = s; // automatically converted to wide string
+** s = "hello"; // automatically converted from ANSI string
+** s = L"hello"; // automatically converted from wide string
+** s += 'a'; // automatically converted from ANSI string
+** s += L'a'; // automatically converted from wide string
+** @endcode
+** Conversions involving ANSI strings use the default user locale. However
+** it is possible to use a custom locale if necessary:
+** @code
+** std::locale locale;
+** efsw::String s;
+** ...
+** std::string s1 = s.toAnsiString(locale);
+** s = efsw::String("hello", locale);
+** @endcode
+**
+** efsw::String defines the most important functions of the
+** standard std::string class: removing, random access, iterating,
+** appending, comparing, etc. However it is a simple class
+** provided for convenience, and you may have to consider using
+** a more optimized class if your program requires complex string
+** handling. The automatic conversion functions will then take
+** care of converting your string to efsw::String whenever EE
+** requires it.
+**
+** Please note that EE also defines a low-level, generic
+** interface for Unicode handling, see the efsw::Utf classes.
+**
+** All credits to Laurent Gomila, i just modified and expanded a little bit the implementation.
+**/
diff --git a/dep/efsw/src/efsw/System.cpp b/dep/efsw/src/efsw/System.cpp
new file mode 100644
index 00000000000..f8767cbc58f
--- /dev/null
+++ b/dep/efsw/src/efsw/System.cpp
@@ -0,0 +1,26 @@
+#include <efsw/System.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+namespace efsw {
+
+void System::sleep( const unsigned long& ms )
+{
+ Platform::System::sleep( ms );
+}
+
+std::string System::getProcessPath()
+{
+ return Platform::System::getProcessPath();
+}
+
+void System::maxFD()
+{
+ Platform::System::maxFD();
+}
+
+Uint64 System::getMaxFD()
+{
+ return Platform::System::getMaxFD();
+}
+
+}
diff --git a/dep/efsw/src/efsw/System.hpp b/dep/efsw/src/efsw/System.hpp
new file mode 100644
index 00000000000..1d6f4a70f91
--- /dev/null
+++ b/dep/efsw/src/efsw/System.hpp
@@ -0,0 +1,26 @@
+#ifndef EFSW_SYSTEM_HPP
+#define EFSW_SYSTEM_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+class System
+{
+ public:
+ /// Sleep for x milliseconds
+ static void sleep( const unsigned long& ms );
+
+ /// @return The process binary path
+ static std::string getProcessPath();
+
+ /// Maximize the number of file descriptors allowed per process in the current OS
+ static void maxFD();
+
+ /// @return The number of supported file descriptors for the process
+ static Uint64 getMaxFD();
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/Thread.cpp b/dep/efsw/src/efsw/Thread.cpp
new file mode 100644
index 00000000000..fff41517dc1
--- /dev/null
+++ b/dep/efsw/src/efsw/Thread.cpp
@@ -0,0 +1,51 @@
+#include <efsw/Thread.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+namespace efsw {
+
+Thread::Thread() :
+ mThreadImpl(NULL),
+ mEntryPoint(NULL)
+{
+}
+
+Thread::~Thread()
+{
+ wait();
+
+ efSAFE_DELETE( mEntryPoint );
+}
+
+void Thread::launch()
+{
+ wait();
+
+ mThreadImpl = new Platform::ThreadImpl( this );
+}
+
+void Thread::wait()
+{
+ if ( mThreadImpl )
+ {
+ mThreadImpl->wait();
+
+ efSAFE_DELETE( mThreadImpl );
+ }
+}
+
+void Thread::terminate()
+{
+ if ( mThreadImpl )
+ {
+ mThreadImpl->terminate();
+
+ efSAFE_DELETE( mThreadImpl );
+ }
+}
+
+void Thread::run()
+{
+ mEntryPoint->run();
+}
+
+}
diff --git a/dep/efsw/src/efsw/Thread.hpp b/dep/efsw/src/efsw/Thread.hpp
new file mode 100644
index 00000000000..c7da9e8b33c
--- /dev/null
+++ b/dep/efsw/src/efsw/Thread.hpp
@@ -0,0 +1,111 @@
+#ifndef EFSW_THREAD_HPP
+#define EFSW_THREAD_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+namespace Platform { class ThreadImpl; }
+namespace Private { struct ThreadFunc; }
+
+/** @brief Thread manager class */
+class Thread {
+ public:
+ typedef void (*FuncType)(void*);
+
+ template <typename F>
+ Thread( F function );
+
+ template <typename F, typename A>
+ Thread( F function, A argument );
+
+ template <typename C>
+ Thread( void(C::*function)(), C* object );
+
+ virtual ~Thread();
+
+ /** Launch the thread */
+ virtual void launch();
+
+ /** Wait the thread until end */
+ void wait();
+
+ /** Terminate the thread */
+ void terminate();
+ protected:
+ Thread();
+ private:
+ friend class Platform::ThreadImpl;
+
+ /** The virtual function to run in the thread */
+ virtual void run();
+
+ Platform::ThreadImpl * mThreadImpl; ///< OS-specific implementation of the thread
+ Private::ThreadFunc * mEntryPoint; ///< Abstraction of the function to run
+};
+
+//! NOTE: Taken from SFML2 threads
+namespace Private {
+
+// Base class for abstract thread functions
+struct ThreadFunc
+{
+ virtual ~ThreadFunc() {}
+ virtual void run() = 0;
+};
+
+// Specialization using a functor (including free functions) with no argument
+template <typename T>
+struct ThreadFunctor : ThreadFunc
+{
+ ThreadFunctor(T functor) : m_functor(functor) {}
+ virtual void run() {m_functor();}
+ T m_functor;
+};
+
+// Specialization using a functor (including free functions) with one argument
+template <typename F, typename A>
+struct ThreadFunctorWithArg : ThreadFunc
+{
+ ThreadFunctorWithArg(F function, A arg) : m_function(function), m_arg(arg) {}
+ virtual void run() {m_function(m_arg);}
+ F m_function;
+ A m_arg;
+};
+
+// Specialization using a member function
+template <typename C>
+struct ThreadMemberFunc : ThreadFunc
+{
+ ThreadMemberFunc(void(C::*function)(), C* object) : m_function(function), m_object(object) {}
+ virtual void run() {(m_object->*m_function)();}
+ void(C::*m_function)();
+ C* m_object;
+};
+
+}
+
+template <typename F>
+Thread::Thread(F functor) :
+ mThreadImpl (NULL),
+ mEntryPoint( new Private::ThreadFunctor<F>(functor) )
+{
+}
+
+template <typename F, typename A>
+Thread::Thread(F function, A argument) :
+ mThreadImpl(NULL),
+ mEntryPoint( new Private::ThreadFunctorWithArg<F efCOMMA A>(function, argument) )
+{
+}
+
+template <typename C>
+Thread::Thread(void(C::*function)(), C* object) :
+ mThreadImpl(NULL),
+ mEntryPoint( new Private::ThreadMemberFunc<C>(function, object) )
+{
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/Utf.hpp b/dep/efsw/src/efsw/Utf.hpp
new file mode 100644
index 00000000000..925a7cc149b
--- /dev/null
+++ b/dep/efsw/src/efsw/Utf.hpp
@@ -0,0 +1,748 @@
+/** NOTE:
+* This code is based on the Utf implementation from SFML2. License zlib/png ( http://www.sfml-dev.org/license.php )
+* The class was modified to fit efsw own needs. This is not the original implementation from SFML2.
+* */
+
+#ifndef EFSW_UTF_HPP
+#define EFSW_UTF_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <locale>
+#include <string>
+#include <cstdlib>
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+template <unsigned int N>
+class Utf;
+
+////////////////////////////////////////////////////////////
+/// \brief Specialization of the Utf template for UTF-8
+///
+////////////////////////////////////////////////////////////
+template <>
+class Utf<8> {
+public :
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single UTF-8 character
+ ///
+ /// Decoding a character means finding its unique 32-bits
+ /// code (called the codepoint) in the Unicode standard.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Codepoint of the decoded UTF-8 character
+ /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-8 character
+ ///
+ /// Encoding a character means converting a unique 32-bits
+ /// code (called the codepoint) in the target encoding, UTF-8.
+ ///
+ /// \param input Codepoint to encode as UTF-8
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out Encode(Uint32 input, Out output, Uint8 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Advance to the next UTF-8 character
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Next(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Count the number of characters of a UTF-8 sequence
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element, thus the
+ /// total size can be different from (begin - end).
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static std::size_t Count(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an ANSI characters range to UTF-8
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a wide characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromWide(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromLatin1(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-8 characters range to ANSI characters
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-8 characters range to wide characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0);
+#endif
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToLatin1(In begin, In end, Out output, char replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-8 characters range to UTF-8
+ ///
+ /// This functions does nothing more than a direct copy;
+ /// it is defined only to provide the same interface as other
+ /// specializations of the efsw::Utf<> template, and allow
+ /// generic code to be written on top of it.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out toUtf8(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-8 characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf16(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-8 characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf32(In begin, In end, Out output);
+};
+
+////////////////////////////////////////////////////////////
+/// \brief Specialization of the Utf template for UTF-16
+///
+////////////////////////////////////////////////////////////
+template <>
+class Utf<16>
+{
+public :
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single UTF-16 character
+ ///
+ /// Decoding a character means finding its unique 32-bits
+ /// code (called the codepoint) in the Unicode standard.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Codepoint of the decoded UTF-16 character
+ /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-16 character
+ ///
+ /// Encoding a character means converting a unique 32-bits
+ /// code (called the codepoint) in the target encoding, UTF-16.
+ ///
+ /// \param input Codepoint to encode as UTF-16
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out Encode(Uint32 input, Out output, Uint16 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Advance to the next UTF-16 character
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Next(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Count the number of characters of a UTF-16 sequence
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element, thus the
+ /// total size can be different from (begin - end).
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static std::size_t Count(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an ANSI characters range to UTF-16
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a wide characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromWide(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromLatin1(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to ANSI characters
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to wide characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0);
+#endif
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToLatin1(In begin, In end, Out output, char replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-16 characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out toUtf8(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-16 characters range to UTF-16
+ ///
+ /// This functions does nothing more than a direct copy;
+ /// it is defined only to provide the same interface as other
+ /// specializations of the efsw::Utf<> template, and allow
+ /// generic code to be written on top of it.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf16(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-16 characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf32(In begin, In end, Out output);
+};
+
+////////////////////////////////////////////////////////////
+/// \brief Specialization of the Utf template for UTF-32
+///
+////////////////////////////////////////////////////////////
+template <>
+class Utf<32>
+{
+public :
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single UTF-32 character
+ ///
+ /// Decoding a character means finding its unique 32-bits
+ /// code (called the codepoint) in the Unicode standard.
+ /// For UTF-32, the character value is the same as the codepoint.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Codepoint of the decoded UTF-32 character
+ /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-32 character
+ ///
+ /// Encoding a character means converting a unique 32-bits
+ /// code (called the codepoint) in the target encoding, UTF-32.
+ /// For UTF-32, the codepoint is the same as the character value.
+ ///
+ /// \param input Codepoint to encode as UTF-32
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out Encode(Uint32 input, Out output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Advance to the next UTF-32 character
+ ///
+ /// This function is trivial for UTF-32, which can store
+ /// every character in a single storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Next(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Count the number of characters of a UTF-32 sequence
+ ///
+ /// This function is trivial for UTF-32, which can store
+ /// every character in a single storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static std::size_t Count(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an ANSI characters range to UTF-32
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a wide characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromWide(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromLatin1(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-32 characters range to ANSI characters
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-32 characters range to wide characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0);
+#endif
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToLatin1(In begin, In end, Out output, char replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-32 characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out toUtf8(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-32 characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf16(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-32 characters range to UTF-32
+ ///
+ /// This functions does nothing more than a direct copy;
+ /// it is defined only to provide the same interface as other
+ /// specializations of the efsw::Utf<> template, and allow
+ /// generic code to be written on top of it.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf32(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single ANSI character to UTF-32
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param input Input ANSI character
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Converted character
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static Uint32 DecodeAnsi(In input, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single wide character to UTF-32
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param input Input wide character
+ ///
+ /// \return Converted character
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static Uint32 DecodeWide(In input);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-32 character to ANSI
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param codepoint Iterator pointing to the beginning of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to skip it)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out EncodeAnsi(Uint32 codepoint, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-32 character to wide
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param codepoint Iterator pointing to the beginning of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement if the input character is not convertible to wide (use 0 to skip it)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out EncodeWide(Uint32 codepoint, Out output, wchar_t replacement = 0);
+#endif
+};
+
+#include "Utf.inl"
+
+// Make typedefs to get rid of the template syntax
+typedef Utf<8> Utf8;
+typedef Utf<16> Utf16;
+typedef Utf<32> Utf32;
+
+}
+#endif
+
+////////////////////////////////////////////////////////////
+/// \class efsw::Utf
+/// \ingroup system
+///
+/// Utility class providing generic functions for UTF conversions.
+///
+/// efsw::Utf is a low-level, generic interface for counting, iterating,
+/// encoding and decoding Unicode characters and strings. It is able
+/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings.
+///
+/// efsw::Utf<X> functions are all static, these classes are not meant to
+/// be instanciated. All the functions are template, so that you
+/// can use any character / string type for a given encoding.
+///
+/// It has 3 specializations:
+/// \li efsw::Utf<8> (typedef'd to efsw::Utf8)
+/// \li efsw::Utf<16> (typedef'd to efsw::Utf16)
+/// \li efsw::Utf<32> (typedef'd to efsw::Utf32)
+///
+////////////////////////////////////////////////////////////
diff --git a/dep/efsw/src/efsw/Utf.inl b/dep/efsw/src/efsw/Utf.inl
new file mode 100644
index 00000000000..db8fd5d61ee
--- /dev/null
+++ b/dep/efsw/src/efsw/Utf.inl
@@ -0,0 +1,671 @@
+// References :
+// http://www.unicode.org/
+// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
+// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h
+// http://people.w3.org/rishida/scripts/uniview/conversion
+////////////////////////////////////////////////////////////
+
+template <typename In>
+In Utf<8>::Decode(In begin, In end, Uint32& output, Uint32 replacement)
+{
+ // Some useful precomputed data
+ static const int trailing[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
+ };
+ static const Uint32 offsets[6] =
+ {
+ 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080
+ };
+
+ // Decode the character
+ int trailingBytes = trailing[static_cast<Uint8>(*begin)];
+ if (begin + trailingBytes < end)
+ {
+ output = 0;
+ switch (trailingBytes)
+ {
+ case 5 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 4 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 3 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 2 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 1 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 0 : output += static_cast<Uint8>(*begin++);
+ }
+ output -= offsets[trailingBytes];
+ }
+ else
+ {
+ // Incomplete character
+ begin = end;
+ output = replacement;
+ }
+
+ return begin;
+}
+
+template <typename Out>
+Out Utf<8>::Encode(Uint32 input, Out output, Uint8 replacement)
+{
+ // Some useful precomputed data
+ static const Uint8 firstBytes[7] =
+ {
+ 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
+ };
+
+ // Encode the character
+ if ((input > 0x0010FFFF) || ((input >= 0xD800) && (input <= 0xDBFF)))
+ {
+ // Invalid character
+ if (replacement)
+ *output++ = replacement;
+ }
+ else
+ {
+ // Valid character
+
+ // Get the number of bytes to write
+ int bytesToWrite = 1;
+ if (input < 0x80) bytesToWrite = 1;
+ else if (input < 0x800) bytesToWrite = 2;
+ else if (input < 0x10000) bytesToWrite = 3;
+ else if (input <= 0x0010FFFF) bytesToWrite = 4;
+
+ // Extract the bytes to write
+ Uint8 bytes[4];
+ switch (bytesToWrite)
+ {
+ case 4 : bytes[3] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 3 : bytes[2] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 2 : bytes[1] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 1 : bytes[0] = static_cast<Uint8> (input | firstBytes[bytesToWrite]);
+ }
+
+ // Add them to the output
+ const Uint8* currentByte = bytes;
+ switch (bytesToWrite)
+ {
+ case 4 : *output++ = *currentByte++;
+ case 3 : *output++ = *currentByte++;
+ case 2 : *output++ = *currentByte++;
+ case 1 : *output++ = *currentByte++;
+ }
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<8>::Next(In begin, In end)
+{
+ Uint32 codepoint;
+ return Decode(begin, end, codepoint);
+}
+
+template <typename In>
+std::size_t Utf<8>::Count(In begin, In end)
+{
+ std::size_t length = 0;
+ while (begin < end)
+ {
+ begin = Next(begin, end);
+ ++length;
+ }
+
+ return length;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::FromAnsi(In begin, In end, Out output, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeAnsi(*begin++, locale);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::FromWide(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeWide(*begin++);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::FromLatin1(In begin, In end, Out output)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ output = Encode(*begin++, output);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeAnsi(codepoint, output, replacement, locale);
+ }
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename In, typename Out>
+Out Utf<8>::ToWide(In begin, In end, Out output, wchar_t replacement)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeWide(codepoint, output, replacement);
+ }
+
+ return output;
+}
+#endif
+
+template <typename In, typename Out>
+Out Utf<8>::ToLatin1(In begin, In end, Out output, char replacement)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ *output++ = codepoint < 256 ? static_cast<char>(codepoint) : replacement;
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::toUtf8(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::ToUtf16(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<16>::Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::ToUtf32(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ *output++ = codepoint;
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<16>::Decode(In begin, In end, Uint32& output, Uint32 replacement)
+{
+ Uint16 first = *begin++;
+
+ // If it's a surrogate pair, first convert to a single UTF-32 character
+ if ((first >= 0xD800) && (first <= 0xDBFF))
+ {
+ if (begin < end)
+ {
+ Uint32 second = *begin++;
+ if ((second >= 0xDC00) && (second <= 0xDFFF))
+ {
+ // The second element is valid: convert the two elements to a UTF-32 character
+ output = static_cast<Uint32>(((first - 0xD800) << 10) + (second - 0xDC00) + 0x0010000);
+ }
+ else
+ {
+ // Invalid character
+ output = replacement;
+ }
+ }
+ else
+ {
+ // Invalid character
+ begin = end;
+ output = replacement;
+ }
+ }
+ else
+ {
+ // We can make a direct copy
+ output = first;
+ }
+
+ return begin;
+}
+
+template <typename Out>
+Out Utf<16>::Encode(Uint32 input, Out output, Uint16 replacement)
+{
+ if (input < 0xFFFF)
+ {
+ // The character can be copied directly, we just need to check if it's in the valid range
+ if ((input >= 0xD800) && (input <= 0xDFFF))
+ {
+ // Invalid character (this range is reserved)
+ if (replacement)
+ *output++ = replacement;
+ }
+ else
+ {
+ // Valid character directly convertible to a single UTF-16 character
+ *output++ = static_cast<Uint16>(input);
+ }
+ }
+ else if (input > 0x0010FFFF)
+ {
+ // Invalid character (greater than the maximum unicode value)
+ if (replacement)
+ *output++ = replacement;
+ }
+ else
+ {
+ // The input character will be converted to two UTF-16 elements
+ input -= 0x0010000;
+ *output++ = static_cast<Uint16>((input >> 10) + 0xD800);
+ *output++ = static_cast<Uint16>((input & 0x3FFUL) + 0xDC00);
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<16>::Next(In begin, In end)
+{
+ Uint32 codepoint;
+ return Decode(begin, end, codepoint);
+}
+
+template <typename In>
+std::size_t Utf<16>::Count(In begin, In end)
+{
+ std::size_t length = 0;
+ while (begin < end)
+ {
+ begin = Next(begin, end);
+ ++length;
+ }
+
+ return length;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::FromAnsi(In begin, In end, Out output, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeAnsi(*begin++, locale);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::FromWide(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeWide(*begin++);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::FromLatin1(In begin, In end, Out output)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeAnsi(codepoint, output, replacement, locale);
+ }
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename In, typename Out>
+Out Utf<16>::ToWide(In begin, In end, Out output, wchar_t replacement)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeWide(codepoint, output, replacement);
+ }
+
+ return output;
+}
+#endif
+
+template <typename In, typename Out>
+Out Utf<16>::ToLatin1(In begin, In end, Out output, char replacement)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ {
+ *output++ = *begin < 256 ? static_cast<char>(*begin) : replacement;
+ begin++;
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::toUtf8(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<8>::Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::ToUtf16(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::ToUtf32(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ *output++ = codepoint;
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<32>::Decode(In begin, In end, Uint32& output, Uint32)
+{
+ output = *begin++;
+ return begin;
+}
+
+template <typename Out>
+Out Utf<32>::Encode(Uint32 input, Out output, Uint32 replacement)
+{
+ *output++ = input;
+ return output;
+}
+
+template <typename In>
+In Utf<32>::Next(In begin, In end)
+{
+ return ++begin;
+}
+
+template <typename In>
+std::size_t Utf<32>::Count(In begin, In end)
+{
+ return begin - end;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::FromAnsi(In begin, In end, Out output, const std::locale& locale)
+{
+ while (begin < end)
+ *output++ = DecodeAnsi(*begin++, locale);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::FromWide(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = DecodeWide(*begin++);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::FromLatin1(In begin, In end, Out output)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
+{
+ while (begin < end)
+ output = EncodeAnsi(*begin++, output, replacement, locale);
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename In, typename Out>
+Out Utf<32>::ToWide(In begin, In end, Out output, wchar_t replacement)
+{
+ while (begin < end)
+ output = EncodeWide(*begin++, output, replacement);
+
+ return output;
+}
+#endif
+
+template <typename In, typename Out>
+Out Utf<32>::ToLatin1(In begin, In end, Out output, char replacement)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ {
+ *output++ = *begin < 256 ? static_cast<char>(*begin) : replacement;
+ begin++;
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::toUtf8(In begin, In end, Out output)
+{
+ while (begin < end)
+ output = Utf<8>::Encode(*begin++, output);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::ToUtf16(In begin, In end, Out output)
+{
+ while (begin < end)
+ output = Utf<16>::Encode(*begin++, output);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::ToUtf32(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In>
+Uint32 Utf<32>::DecodeAnsi(In input, const std::locale& locale)
+{
+ // On Windows, gcc's standard library (glibc++) has almost
+ // no support for Unicode stuff. As a consequence, in this
+ // context we can only use the default locale and ignore
+ // the one passed as parameter.
+
+ #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \
+ (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \
+ !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */
+
+ wchar_t character = 0;
+ mbtowc(&character, &input, 1);
+ return static_cast<Uint32>(character);
+
+ #else
+ // Get the facet of the locale which deals with character conversion
+ #ifndef EFSW_NO_WIDECHAR
+ const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
+ #else
+ const std::ctype<char>& facet = std::use_facet< std::ctype<char> >(locale);
+ #endif
+
+ // Use the facet to convert each character of the input string
+ return static_cast<Uint32>(facet.widen(input));
+
+ #endif
+}
+
+template <typename In>
+Uint32 Utf<32>::DecodeWide(In input)
+{
+ // The encoding of wide characters is not well defined and is left to the system;
+ // however we can safely assume that it is UCS-2 on Windows and
+ // UCS-4 on Unix systems.
+ // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4,
+ // and UCS-4 *is* UTF-32).
+
+ return input;
+}
+
+template <typename Out>
+Out Utf<32>::EncodeAnsi(Uint32 codepoint, Out output, char replacement, const std::locale& locale)
+{
+ // On Windows, gcc's standard library (glibc++) has almost
+ // no support for Unicode stuff. As a consequence, in this
+ // context we can only use the default locale and ignore
+ // the one passed as parameter.
+
+ #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \
+ (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \
+ !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */
+
+ char character = 0;
+ if (wctomb(&character, static_cast<wchar_t>(codepoint)) >= 0)
+ *output++ = character;
+ else if (replacement)
+ *output++ = replacement;
+
+ return output;
+
+ #else
+ // Get the facet of the locale which deals with character conversion
+ #ifndef EFSW_NO_WIDECHAR
+ const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
+ #else
+ const std::ctype<char>& facet = std::use_facet< std::ctype<char> >(locale);
+ #endif
+
+ // Use the facet to convert each character of the input string
+ *output++ = facet.narrow(static_cast<wchar_t>(codepoint), replacement);
+
+ return output;
+
+ #endif
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename Out>
+Out Utf<32>::EncodeWide(Uint32 codepoint, Out output, wchar_t replacement)
+{
+ // The encoding of wide characters is not well defined and is left to the system;
+ // however we can safely assume that it is UCS-2 on Windows and
+ // UCS-4 on Unix systems.
+ // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4).
+ // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32).
+
+ switch (sizeof(wchar_t))
+ {
+ case 4:
+ {
+ *output++ = static_cast<wchar_t>(codepoint);
+ break;
+ }
+
+ default:
+ {
+ if ((codepoint <= 0xFFFF) && ((codepoint < 0xD800) || (codepoint > 0xDFFF)))
+ {
+ *output++ = static_cast<wchar_t>(codepoint);
+ }
+ else if (replacement)
+ {
+ *output++ = replacement;
+ }
+ break;
+ }
+ }
+
+ return output;
+}
+#endif
diff --git a/dep/efsw/src/efsw/Watcher.cpp b/dep/efsw/src/efsw/Watcher.cpp
new file mode 100644
index 00000000000..d81c84228ad
--- /dev/null
+++ b/dep/efsw/src/efsw/Watcher.cpp
@@ -0,0 +1,21 @@
+#include <efsw/Watcher.hpp>
+
+namespace efsw {
+
+Watcher::Watcher() :
+ ID(0),
+ Directory(""),
+ Listener(NULL),
+ Recursive(false)
+{
+}
+
+Watcher::Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ) :
+ ID( id ),
+ Directory( directory ),
+ Listener( listener ),
+ Recursive( recursive )
+{
+}
+
+}
diff --git a/dep/efsw/src/efsw/Watcher.hpp b/dep/efsw/src/efsw/Watcher.hpp
new file mode 100644
index 00000000000..5a35cb9a2ac
--- /dev/null
+++ b/dep/efsw/src/efsw/Watcher.hpp
@@ -0,0 +1,30 @@
+#ifndef EFSW_WATCHERIMPL_HPP
+#define EFSW_WATCHERIMPL_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/efsw.hpp>
+
+namespace efsw {
+
+/** @brief Base Watcher class */
+class Watcher
+{
+ public:
+ Watcher();
+
+ Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive );
+
+ virtual ~Watcher() {}
+
+ virtual void watch() {}
+
+ WatchID ID;
+ std::string Directory;
+ FileWatchListener * Listener;
+ bool Recursive;
+ std::string OldFileName;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherFSEvents.cpp b/dep/efsw/src/efsw/WatcherFSEvents.cpp
new file mode 100644
index 00000000000..3a9700c77ec
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherFSEvents.cpp
@@ -0,0 +1,264 @@
+#include <efsw/WatcherFSEvents.hpp>
+#include <efsw/FileWatcherFSEvents.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/Debug.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+namespace efsw {
+
+WatcherFSEvents::WatcherFSEvents() :
+ Watcher(),
+ FWatcher( NULL ),
+ FSStream( NULL ),
+ WatcherGen( NULL ),
+ initializedAsync( false )
+{
+}
+
+WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent ) :
+ Watcher( id, directory, listener, recursive ),
+ FWatcher( NULL ),
+ FSStream( NULL ),
+ WatcherGen( NULL ),
+ initializedAsync( false )
+{
+}
+
+WatcherFSEvents::~WatcherFSEvents()
+{
+ if ( initializedAsync )
+ {
+ FSEventStreamStop( FSStream );
+ FSEventStreamInvalidate( FSStream );
+ }
+
+ if ( NULL != FSStream )
+ {
+ FSEventStreamRelease( FSStream );
+ }
+
+ efSAFE_DELETE( WatcherGen );
+}
+
+void WatcherFSEvents::init()
+{
+ CFStringRef CFDirectory = CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 );
+ CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void **)&CFDirectory, 1, NULL );
+
+ Uint32 streamFlags = kFSEventStreamCreateFlagNone;
+
+ if ( FileWatcherFSEvents::isGranular() )
+ {
+ streamFlags = efswFSEventStreamCreateFlagFileEvents;
+ }
+ else
+ {
+ WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher, Recursive );
+ }
+
+ FSEventStreamContext ctx;
+ /* Initialize context */
+ ctx.version = 0;
+ ctx.info = this;
+ ctx.retain = NULL;
+ ctx.release = NULL;
+ ctx.copyDescription = NULL;
+
+ FSStream = FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags );
+
+ FWatcher->mNeedInit.push_back( this );
+
+ CFRelease( CFDirectoryArray );
+ CFRelease( CFDirectory );
+}
+
+void WatcherFSEvents::initAsync()
+{
+ FSEventStreamScheduleWithRunLoop( FSStream, FWatcher->mRunLoopRef, kCFRunLoopDefaultMode );
+ FSEventStreamStart( FSStream );
+ initializedAsync = true;
+}
+
+void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename )
+{
+ Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), FileSystem::precomposeFileName( filename ), action, oldFilename );
+}
+
+void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, std::string& filePath )
+{
+ if ( flags & efswFSEventStreamEventFlagItemCreated )
+ {
+ if ( FileInfo::exists( path ) )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Add );
+ }
+ }
+
+ if ( flags & efswFSEventsModified )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Modified );
+ }
+
+ if ( flags & efswFSEventStreamEventFlagItemRemoved )
+ {
+ // Since i don't know the order, at least i try to keep the data consistent with the real state
+ if ( !FileInfo::exists( path ) )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Delete );
+ }
+ }
+}
+
+void WatcherFSEvents::handleActions( std::vector<FSEvent>& events )
+{
+ size_t esize = events.size();
+
+ for ( size_t i = 0; i < esize; i++ )
+ {
+ FSEvent& event = events[i];
+
+ if ( event.Flags & ( kFSEventStreamEventFlagUserDropped |
+ kFSEventStreamEventFlagKernelDropped |
+ kFSEventStreamEventFlagEventIdsWrapped |
+ kFSEventStreamEventFlagHistoryDone |
+ kFSEventStreamEventFlagMount |
+ kFSEventStreamEventFlagUnmount |
+ kFSEventStreamEventFlagRootChanged ) )
+ {
+ continue;
+ }
+
+ if ( !Recursive )
+ {
+ /** In case that is not recursive the watcher, ignore the events from subfolders */
+ if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 )
+ {
+ continue;
+ }
+ }
+
+ if ( FileWatcherFSEvents::isGranular() )
+ {
+ std::string dirPath( FileSystem::pathRemoveFileName( event.Path ) );
+ std::string filePath( FileSystem::fileNameFromPath( event.Path ) );
+
+ if ( event.Flags & ( efswFSEventStreamEventFlagItemCreated |
+ efswFSEventStreamEventFlagItemRemoved |
+ efswFSEventStreamEventFlagItemRenamed )
+ )
+ {
+ if ( dirPath != Directory )
+ {
+ DirsChanged.insert( dirPath );
+ }
+ }
+
+ // This is a mess. But it's FSEvents faults, because shrinks events from the same file in one single event ( so there's no order for them )
+ // For example a file could have been added modified and erased, but i can't know if first was erased and then added and modified, or added, then modified and then erased.
+ // I don't know what they were thinking by doing this...
+ efDEBUG( "Event in: %s - flags: %ld\n", path.c_str(), event.Flags );
+
+ if ( event.Flags & efswFSEventStreamEventFlagItemRenamed )
+ {
+ if ( ( i + 1 < esize ) &&
+ ( events[ i + 1 ].Flags & efswFSEventStreamEventFlagItemRenamed ) &&
+ ( events[ i + 1 ].Id == event.Id + 1 )
+ )
+ {
+ FSEvent& nEvent = events[ i + 1 ];
+ std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) );
+ std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) );
+
+ if ( event.Path != nEvent.Path )
+ {
+ if ( dirPath == newDir )
+ {
+ if ( !FileInfo::exists( event.Path ) )
+ {
+ sendFileAction( ID, dirPath, newFilepath, Actions::Moved, filePath );
+ }
+ else
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Moved, newFilepath );
+ }
+ }
+ else
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Delete );
+ sendFileAction( ID, newDir, newFilepath, Actions::Add );
+
+ if ( nEvent.Flags & efswFSEventsModified )
+ {
+ sendFileAction( ID, newDir, newFilepath, Actions::Modified );
+ }
+ }
+ }
+ else
+ {
+ handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath );
+ }
+
+ if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated |
+ efswFSEventStreamEventFlagItemRemoved |
+ efswFSEventStreamEventFlagItemRenamed )
+ )
+ {
+ if ( newDir != Directory )
+ {
+ DirsChanged.insert( newDir );
+ }
+ }
+
+ // Skip the renamed file
+ i++;
+ }
+ else if ( FileInfo::exists( event.Path ) )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Add );
+
+ if ( event.Flags & efswFSEventsModified )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Modified );
+ }
+ }
+ else
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Delete );
+ }
+ }
+ else
+ {
+ handleAddModDel( event.Flags, event.Path, dirPath, filePath );
+ }
+ }
+ else
+ {
+ efDEBUG( "Directory: %s changed\n", event.Path.c_str() );
+ DirsChanged.insert( event.Path );
+ }
+ }
+}
+
+void WatcherFSEvents::process()
+{
+ std::set<std::string>::iterator it = DirsChanged.begin();
+
+ for ( ; it != DirsChanged.end(); it++ )
+ {
+ if ( !FileWatcherFSEvents::isGranular() )
+ {
+ WatcherGen->watchDir( (*it) );
+ }
+ else
+ {
+ sendFileAction( ID, FileSystem::pathRemoveFileName( (*it) ), FileSystem::fileNameFromPath( (*it) ), Actions::Modified );
+ }
+ }
+
+ DirsChanged.clear();
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherFSEvents.hpp b/dep/efsw/src/efsw/WatcherFSEvents.hpp
new file mode 100644
index 00000000000..d4fc5c9a8d3
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherFSEvents.hpp
@@ -0,0 +1,70 @@
+#ifndef EFSW_WATCHERINOTIFY_HPP
+#define EFSW_WATCHERINOTIFY_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileInfo.hpp>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <set>
+#include <vector>
+
+namespace efsw {
+
+class FileWatcherFSEvents;
+
+class FSEvent
+{
+ public:
+ FSEvent( std::string path, long flags, Uint64 id ) :
+ Path( path ),
+ Flags( flags ),
+ Id ( id )
+ {
+ }
+
+ std::string Path;
+ long Flags;
+ Uint64 Id;
+};
+
+class WatcherFSEvents : public Watcher
+{
+ public:
+ WatcherFSEvents();
+
+ WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent = NULL );
+
+ ~WatcherFSEvents();
+
+ void init();
+
+ void initAsync();
+
+ void handleActions( std::vector<FSEvent> & events );
+
+ void process();
+
+ FileWatcherFSEvents * FWatcher;
+
+ FSEventStreamRef FSStream;
+ protected:
+ void handleAddModDel( const Uint32 &flags, const std::string &path, std::string &dirPath, std::string &filePath );
+
+ WatcherGeneric * WatcherGen;
+
+ bool initializedAsync;
+
+ std::set<std::string> DirsChanged;
+
+ void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" );
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherGeneric.cpp b/dep/efsw/src/efsw/WatcherGeneric.cpp
new file mode 100644
index 00000000000..94170d3ce87
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherGeneric.cpp
@@ -0,0 +1,40 @@
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/DirWatcherGeneric.hpp>
+
+namespace efsw
+{
+
+WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ) :
+ Watcher( id, directory, fwl, recursive ),
+ WatcherImpl( fw ),
+ DirWatch( NULL )
+{
+ FileSystem::dirAddSlashAtEnd( Directory );
+
+ DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive, false );
+
+ DirWatch->addChilds( false );
+}
+
+WatcherGeneric::~WatcherGeneric()
+{
+ efSAFE_DELETE( DirWatch );
+}
+
+void WatcherGeneric::watch()
+{
+ DirWatch->watch();
+}
+
+void WatcherGeneric::watchDir( std::string dir )
+{
+ DirWatch->watchDir( dir );
+}
+
+bool WatcherGeneric::pathInWatches( std::string path )
+{
+ return DirWatch->pathInWatches( path );
+}
+
+}
diff --git a/dep/efsw/src/efsw/WatcherGeneric.hpp b/dep/efsw/src/efsw/WatcherGeneric.hpp
new file mode 100644
index 00000000000..8794e921b40
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherGeneric.hpp
@@ -0,0 +1,30 @@
+#ifndef EFSW_WATCHERGENERIC_HPP
+#define EFSW_WATCHERGENERIC_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+namespace efsw
+{
+
+class DirWatcherGeneric;
+
+class WatcherGeneric : public Watcher
+{
+ public:
+ FileWatcherImpl * WatcherImpl;
+ DirWatcherGeneric * DirWatch;
+
+ WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive );
+
+ ~WatcherGeneric();
+
+ void watch();
+
+ void watchDir( std::string dir );
+
+ bool pathInWatches( std::string path );
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherInotify.cpp b/dep/efsw/src/efsw/WatcherInotify.cpp
new file mode 100644
index 00000000000..741641bf43c
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherInotify.cpp
@@ -0,0 +1,35 @@
+#include <efsw/WatcherInotify.hpp>
+
+namespace efsw {
+
+WatcherInotify::WatcherInotify() :
+ Watcher(),
+ Parent( NULL )
+{
+}
+
+WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent ) :
+ Watcher( id, directory, listener, recursive ),
+ Parent( parent ),
+ DirInfo( directory )
+{
+}
+
+bool WatcherInotify::inParentTree( WatcherInotify * parent )
+{
+ WatcherInotify * tNext = Parent;
+
+ while ( NULL != tNext )
+ {
+ if ( tNext == parent )
+ {
+ return true;
+ }
+
+ tNext = tNext->Parent;
+ }
+
+ return false;
+}
+
+}
diff --git a/dep/efsw/src/efsw/WatcherInotify.hpp b/dep/efsw/src/efsw/WatcherInotify.hpp
new file mode 100644
index 00000000000..1caf399679b
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherInotify.hpp
@@ -0,0 +1,25 @@
+#ifndef EFSW_WATCHERINOTIFY_HPP
+#define EFSW_WATCHERINOTIFY_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/FileInfo.hpp>
+
+namespace efsw {
+
+class WatcherInotify : public Watcher
+{
+ public:
+ WatcherInotify();
+
+ WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent = NULL );
+
+ bool inParentTree( WatcherInotify * parent );
+
+ WatcherInotify * Parent;
+
+ FileInfo DirInfo;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherKqueue.cpp b/dep/efsw/src/efsw/WatcherKqueue.cpp
new file mode 100644
index 00000000000..8347fb53439
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherKqueue.cpp
@@ -0,0 +1,667 @@
+#include <efsw/WatcherKqueue.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <efsw/Debug.hpp>
+#include <efsw/String.hpp>
+#include <efsw/System.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileWatcherKqueue.hpp>
+
+#define KEVENT_RESERVE_VALUE (10)
+
+#ifndef O_EVTONLY
+#define O_EVTONLY (O_RDONLY | O_NONBLOCK)
+#endif
+
+namespace efsw {
+
+int comparator(const void* ke1, const void* ke2)
+{
+ const KEvent * kev1 = reinterpret_cast<const KEvent*>( ke1 );
+ const KEvent * kev2 = reinterpret_cast<const KEvent*>( ke2 );
+
+ if ( NULL != kev2->udata )
+ {
+ FileInfo * fi1 = reinterpret_cast<FileInfo*>( kev1->udata );
+ FileInfo * fi2 = reinterpret_cast<FileInfo*>( kev2->udata );
+
+ return strcmp( fi1->Filepath.c_str(), fi2->Filepath.c_str() );
+ }
+
+ return 1;
+}
+
+WatcherKqueue::WatcherKqueue(WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent ) :
+ Watcher( watchid, dirname, listener, recursive ),
+ mLastWatchID(0),
+ mChangeListCount( 0 ),
+ mKqueue( kqueue() ),
+ mWatcher( watcher ),
+ mParent( parent ),
+ mInitOK( true ),
+ mErrno(0)
+{
+ if ( -1 == mKqueue )
+ {
+ efDEBUG( "kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n", Directory.c_str(), mWatcher->mFileDescriptorCount );
+
+ mInitOK = false;
+ mErrno = errno;
+ }
+ else
+ {
+ mWatcher->addFD();
+ }
+}
+
+WatcherKqueue::~WatcherKqueue()
+{
+ // Remove the childs watchers ( sub-folders watches )
+ removeAll();
+
+ for ( size_t i = 0; i < mChangeListCount; i++ )
+ {
+ if ( NULL != mChangeList[i].udata )
+ {
+ FileInfo * fi = reinterpret_cast<FileInfo*>( mChangeList[i].udata );
+
+ efSAFE_DELETE( fi );
+ }
+ }
+
+ close( mKqueue );
+
+ mWatcher->removeFD();
+}
+
+void WatcherKqueue::addAll()
+{
+ if ( -1 == mKqueue )
+ {
+ return;
+ }
+
+ // scan directory and call addFile(name, false) on each file
+ FileSystem::dirAddSlashAtEnd( Directory );
+
+ efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str());
+
+ // add base dir
+ int fd = open( Directory.c_str(), O_EVTONLY );
+
+ if ( -1 == fd )
+ {
+ efDEBUG( "addAll(): Couldn't open folder: %s\n", Directory.c_str() );
+
+ if ( EACCES != errno )
+ {
+ mInitOK = false;
+ }
+
+ mErrno = errno;
+
+ return;
+ }
+
+ mDirSnap.setDirectoryInfo( Directory );
+ mDirSnap.scan();
+
+ mChangeList.resize( KEVENT_RESERVE_VALUE );
+
+ // Creates the kevent for the folder
+ EV_SET(
+ &mChangeList[0],
+ fd,
+ EVFILT_VNODE,
+ EV_ADD | EV_ENABLE | EV_ONESHOT,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
+ 0,
+ 0
+ );
+
+ mWatcher->addFD();
+
+ // Get the files and directories from the directory
+ FileInfoMap files = FileSystem::filesInfoFromPath( Directory );
+
+ for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ )
+ {
+ FileInfo& fi = it->second;
+
+ if ( fi.isRegularFile() )
+ {
+ // Add the regular files kevent
+ addFile( fi.Filepath , false );
+ }
+ else if ( Recursive && fi.isDirectory() && fi.isReadable() )
+ {
+ // Create another watcher for the subfolders ( if recursive )
+ WatchID id = addWatch( fi.Filepath, Listener, Recursive, this );
+
+ // If the watcher is not adding the watcher means that the directory was created
+ if ( id > 0 && !mWatcher->isAddingWatcher() )
+ {
+ handleFolderAction( fi.Filepath, Actions::Add );
+ }
+ }
+ }
+}
+
+void WatcherKqueue::removeAll()
+{
+ efDEBUG( "removeAll(): Removing all child watchers\n" );
+
+ std::list<WatchID> erase;
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() );
+
+ erase.push_back( it->second->ID );
+ }
+
+ for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ )
+ {
+ removeWatch( *eit );
+ }
+}
+
+void WatcherKqueue::addFile(const std::string& name, bool emitEvents)
+{
+ efDEBUG( "addFile(): Added: %s\n", name.c_str() );
+
+ // Open the file to get the file descriptor
+ int fd = open( name.c_str(), O_EVTONLY );
+
+ if( fd == -1 )
+ {
+ efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n", name.c_str(), mWatcher->mFileDescriptorCount );
+
+ Errors::Log::createLastError( Errors::FileNotReadable, name );
+
+ if ( EACCES != errno )
+ {
+ mInitOK = false;
+ }
+
+ mErrno = errno;
+
+ return;
+ }
+
+ mWatcher->addFD();
+
+ // increase the file kevent file count
+ mChangeListCount++;
+
+ if ( mChangeListCount + KEVENT_RESERVE_VALUE > mChangeList.size() &&
+ mChangeListCount % KEVENT_RESERVE_VALUE == 0 )
+ {
+ size_t reserve_size = mChangeList.size() + KEVENT_RESERVE_VALUE;
+ mChangeList.resize( reserve_size );
+ efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual size %ld.\n", Directory.c_str(), reserve_size, mChangeListCount );
+ }
+
+ // create entry
+ FileInfo * entry = new FileInfo( name );
+
+ // set the event data at the end of the list
+ EV_SET(
+ &mChangeList[mChangeListCount],
+ fd,
+ EVFILT_VNODE,
+ EV_ADD | EV_ENABLE | EV_ONESHOT,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
+ 0,
+ (void*)entry
+ );
+
+ // qsort sort the list by name
+ qsort(&mChangeList[1], mChangeListCount, sizeof(KEvent), comparator);
+
+ // handle action
+ if( emitEvents )
+ {
+ handleAction(name, Actions::Add);
+ }
+}
+
+void WatcherKqueue::removeFile( const std::string& name, bool emitEvents )
+{
+ efDEBUG( "removeFile(): Trying to remove file: %s\n", name.c_str() );
+
+ // bsearch
+ KEvent target;
+
+ // Create a temporary file info to search the kevent ( searching the directory )
+ FileInfo tempEntry( name );
+
+ target.udata = &tempEntry;
+
+ // Search the kevent
+ KEvent * ke = (KEvent*)bsearch(&target, &mChangeList[0], mChangeListCount + 1, sizeof(KEvent), comparator);
+
+ // Trying to remove a non-existing file?
+ if( !ke )
+ {
+ Errors::Log::createLastError( Errors::FileNotFound, name );
+ efDEBUG( "File not removed\n" );
+ return;
+ }
+
+ efDEBUG( "File removed\n" );
+
+ // handle action
+ if ( emitEvents )
+ {
+ handleAction( name, Actions::Delete );
+ }
+
+ // Delete the user data ( FileInfo ) from the kevent closed
+ FileInfo * del = reinterpret_cast<FileInfo*>( ke->udata );
+
+ efSAFE_DELETE( del );
+
+ // close the file descriptor from the kevent
+ close( ke->ident );
+
+ mWatcher->removeFD();
+
+ memset(ke, 0, sizeof(KEvent));
+
+ // move end to current
+ memcpy(ke, &mChangeList[mChangeListCount], sizeof(KEvent));
+ memset(&mChangeList[mChangeListCount], 0, sizeof(KEvent));
+ --mChangeListCount;
+}
+
+void WatcherKqueue::rescan()
+{
+ efDEBUG( "rescan(): Rescanning: %s\n", Directory.c_str() );
+
+ DirectorySnapshotDiff Diff = mDirSnap.scan();
+
+ if ( Diff.DirChanged )
+ {
+ sendDirChanged();
+ }
+
+ if ( Diff.changed() )
+ {
+ FileInfoList::iterator it;
+ MovedList::iterator mit;
+
+ /// Files
+ DiffIterator( FilesCreated )
+ {
+ addFile( (*it).Filepath );
+ }
+
+ DiffIterator( FilesModified )
+ {
+ handleAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( FilesDeleted )
+ {
+ removeFile( (*it).Filepath );
+ }
+
+ DiffMovedIterator( FilesMoved )
+ {
+ handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
+ removeFile( Directory + (*mit).first, false );
+ addFile( (*mit).second.Filepath, false );
+ }
+
+ /// Directories
+ DiffIterator( DirsCreated )
+ {
+ handleFolderAction( (*it).Filepath, Actions::Add );
+ addWatch( (*it).Filepath, Listener, Recursive, this );
+ }
+
+ DiffIterator( DirsModified )
+ {
+ handleFolderAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( DirsDeleted )
+ {
+ handleFolderAction( (*it).Filepath, Actions::Delete );
+
+ Watcher * watch = findWatcher( (*it).Filepath );
+
+ if ( NULL != watch )
+ {
+ removeWatch( watch->ID );
+
+ }
+ }
+
+ DiffMovedIterator( DirsMoved )
+ {
+ moveDirectory( Directory + (*mit).first, (*mit).second.Filepath );
+ }
+ }
+}
+
+WatchID WatcherKqueue::watchingDirectory( std::string dir )
+{
+ Watcher * watch = findWatcher( dir );
+
+ if ( NULL != watch )
+ {
+ return watch->ID;
+ }
+
+ return Errors::FileNotFound;
+}
+
+void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename )
+{
+ Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action, FileSystem::fileNameFromPath( oldFilename ) );
+}
+
+void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action , const std::string &oldFilename )
+{
+ FileSystem::dirRemoveSlashAtEnd( filename );
+
+ handleAction( filename, action, oldFilename );
+}
+
+void WatcherKqueue::sendDirChanged()
+{
+ if ( NULL != mParent )
+ {
+ Listener->handleFileAction( mParent->ID, mParent->Directory, FileSystem::fileNameFromPath( Directory ), Actions::Modified );
+ }
+}
+
+void WatcherKqueue::watch()
+{
+ if ( -1 == mKqueue )
+ {
+ return;
+ }
+
+ int nev = 0;
+ KEvent event;
+
+ // First iterate the childs, to get the events from the deepest folder, to the watcher childs
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
+ {
+ it->second->watch();
+ }
+
+ bool needScan = false;
+
+ // Then we get the the events of the current folder
+ while( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, &mWatcher->mTimeOut ) ) != 0 )
+ {
+ // An error ocurred?
+ if( nev == -1 )
+ {
+ efDEBUG( "watch(): Error on directory %s\n", Directory.c_str() );
+ perror("kevent");
+ break;
+ }
+ else
+ {
+ FileInfo * entry = NULL;
+
+ // If udate == NULL means that it is the fisrt element of the change list, the folder.
+ // otherwise it is an event of some file inside the folder
+ if( ( entry = reinterpret_cast<FileInfo*> ( event.udata ) ) != NULL )
+ {
+ efDEBUG( "watch(): File: %s ", entry->Filepath.c_str() );
+
+ // If the event flag is delete... the file was deleted
+ if ( event.fflags & NOTE_DELETE )
+ {
+ efDEBUG( "deleted\n" );
+
+ mDirSnap.removeFile( entry->Filepath );
+
+ removeFile( entry->Filepath );
+ }
+ else if ( event.fflags & NOTE_EXTEND ||
+ event.fflags & NOTE_WRITE ||
+ event.fflags & NOTE_ATTRIB
+ )
+ {
+ // The file was modified
+ efDEBUG( "modified\n" );
+
+ FileInfo fi( entry->Filepath );
+
+ if ( fi != *entry )
+ {
+ *entry = fi;
+
+ mDirSnap.updateFile( entry->Filepath );
+
+ handleAction( entry->Filepath, efsw::Actions::Modified );
+ }
+ }
+ else if ( event.fflags & NOTE_RENAME )
+ {
+ efDEBUG( "moved\n" );
+
+ needScan = true;
+ }
+ }
+ else
+ {
+ needScan = true;
+ }
+ }
+ }
+
+ if ( needScan )
+ {
+ rescan();
+ }
+}
+
+Watcher * WatcherKqueue::findWatcher( const std::string path )
+{
+ WatchMap::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return it->second;
+ }
+ }
+
+ return NULL;
+}
+
+void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents )
+{
+ // Update the directory path if it's a watcher
+ std::string opath2( oldPath );
+ FileSystem::dirAddSlashAtEnd( opath2 );
+
+ Watcher * watch = findWatcher( opath2 );
+
+ if ( NULL != watch )
+ {
+ watch->Directory = opath2;
+ }
+
+ if ( emitEvents )
+ {
+ handleFolderAction( newPath, efsw::Actions::Moved, oldPath );
+ }
+}
+
+WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive , WatcherKqueue *parent)
+{
+ static long s_fc = 0;
+ static bool s_ug = false;
+
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ // This should never happen here
+ if( !FileSystem::isDirectory( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( pathInWatches( dir ) || pathInParent( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( NULL != parent && FileSystem::isRemoteFS( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, dir );
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+
+ if ( pathInWatches( link ) || pathInParent( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, link );
+ }
+ else if ( !mWatcher->linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, link );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ if ( mWatcher->availablesFD() )
+ {
+ WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent );
+
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+
+ watch->addAll();
+
+ s_fc++;
+
+ // if failed to open the directory... erase the watcher
+ if ( !watch->initOK() )
+ {
+ int le = watch->lastErrno();
+
+ mWatches.erase( watch->ID );
+
+ efSAFE_DELETE( watch );
+
+ mLastWatchID--;
+
+ // Probably the folder has too many files, create a generic watcher
+ if ( EACCES != le )
+ {
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
+
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::Unspecified, link );
+ }
+ }
+ }
+ else
+ {
+ if ( !s_ug )
+ {
+ efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders added: %ld\n", mWatcher->mFileDescriptorCount, s_fc );
+ s_ug = true;
+ }
+
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
+
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ }
+
+ return mLastWatchID;
+}
+
+bool WatcherKqueue::initOK()
+{
+ return mInitOK;
+}
+
+void WatcherKqueue::removeWatch( WatchID watchid )
+{
+ WatchMap::iterator iter = mWatches.find(watchid);
+
+ if(iter == mWatches.end())
+ return;
+
+ Watcher * watch = iter->second;
+
+ mWatches.erase(iter);
+
+ efSAFE_DELETE( watch );
+}
+
+bool WatcherKqueue::pathInWatches( const std::string& path )
+{
+ return NULL != findWatcher( path );
+}
+
+bool WatcherKqueue::pathInParent( const std::string &path )
+{
+ WatcherKqueue * pNext = mParent;
+
+ while ( NULL != pNext )
+ {
+ if ( pNext->pathInWatches( path ) )
+ {
+ return true;
+ }
+
+ pNext = pNext->mParent;
+ }
+
+ if ( mWatcher->pathInWatches( path ) )
+ {
+ return true;
+ }
+
+ if ( path == Directory )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+int WatcherKqueue::lastErrno()
+{
+ return mErrno;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherKqueue.hpp b/dep/efsw/src/efsw/WatcherKqueue.hpp
new file mode 100644
index 00000000000..4babbe73354
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherKqueue.hpp
@@ -0,0 +1,94 @@
+#ifndef EFSW_WATCHEROSX_HPP
+#define EFSW_WATCHEROSX_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <map>
+#include <vector>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <efsw/DirectorySnapshot.hpp>
+
+namespace efsw
+{
+
+class FileWatcherKqueue;
+class WatcherKqueue;
+
+typedef struct kevent KEvent;
+
+/// type for a map from WatchID to WatcherKqueue pointer
+typedef std::map<WatchID, Watcher*> WatchMap;
+
+class WatcherKqueue : public Watcher
+{
+ public:
+ WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent = NULL );
+
+ virtual ~WatcherKqueue();
+
+ void addFile( const std::string& name, bool emitEvents = true );
+
+ void removeFile( const std::string& name, bool emitEvents = true );
+
+ // called when the directory is actually changed
+ // means a file has been added or removed
+ // rescans the watched directory adding/removing files and sending notices
+ void rescan();
+
+ void handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename = "" );
+
+ void handleFolderAction( std::string filename, efsw::Action action, const std::string& oldFilename = "" );
+
+ void addAll();
+
+ void removeAll();
+
+ WatchID watchingDirectory( std::string dir );
+
+ void watch();
+
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherKqueue * parent);
+
+ void removeWatch (WatchID watchid );
+
+ bool initOK();
+
+ int lastErrno();
+ protected:
+ WatchMap mWatches;
+ int mLastWatchID;
+
+ // index 0 is always the directory
+ std::vector<KEvent> mChangeList;
+ size_t mChangeListCount;
+ DirectorySnapshot mDirSnap;
+
+ /// The descriptor for the kqueue
+ int mKqueue;
+
+ FileWatcherKqueue * mWatcher;
+
+ WatcherKqueue * mParent;
+
+ bool mInitOK;
+ int mErrno;
+
+ bool pathInWatches( const std::string& path );
+
+ bool pathInParent( const std::string& path );
+
+ Watcher * findWatcher( const std::string path );
+
+ void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true );
+
+ void sendDirChanged();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherWin32.cpp b/dep/efsw/src/efsw/WatcherWin32.cpp
new file mode 100644
index 00000000000..01d7b0fcd99
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherWin32.cpp
@@ -0,0 +1,150 @@
+#include <efsw/WatcherWin32.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw
+{
+
+/// Unpacks events and passes them to a user defined callback.
+void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
+{
+ char szFile[MAX_PATH];
+ PFILE_NOTIFY_INFORMATION pNotify;
+ WatcherStructWin32 * tWatch = (WatcherStructWin32*) lpOverlapped;
+ WatcherWin32 * pWatch = tWatch->Watch;
+ size_t offset = 0;
+
+ if (dwNumberOfBytesTransfered == 0)
+ {
+ RefreshWatch(tWatch); // If dwNumberOfBytesTransfered == 0, it means the buffer overflowed (too many changes between GetOverlappedResults calls). Those events are lost, but at least we can refresh so subsequent changes are seen again.
+ return;
+ }
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ do
+ {
+ bool skip = false;
+
+ pNotify = (PFILE_NOTIFY_INFORMATION) &pWatch->mBuffer[offset];
+ offset += pNotify->NextEntryOffset;
+
+ int count = WideCharToMultiByte(CP_UTF8, 0, pNotify->FileName,
+ pNotify->FileNameLength / sizeof(WCHAR),
+ szFile, MAX_PATH - 1, NULL, NULL);
+ szFile[count] = TEXT('\0');
+
+ std::string nfile( szFile );
+
+ if ( FILE_ACTION_MODIFIED == pNotify->Action )
+ {
+ FileInfo fifile( std::string( pWatch->DirName ) + nfile );
+
+ if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && pWatch->LastModifiedEvent.file.Size == fifile.Size && pWatch->LastModifiedEvent.fileName == nfile )
+ {
+ skip = true;
+ }
+
+ pWatch->LastModifiedEvent.fileName = nfile;
+ pWatch->LastModifiedEvent.file = fifile;
+ }
+
+ if ( !skip )
+ {
+ pWatch->Watch->handleAction(pWatch, nfile, pNotify->Action);
+ }
+ } while (pNotify->NextEntryOffset != 0);
+ }
+
+ if (!pWatch->StopNow)
+ {
+ RefreshWatch(tWatch);
+ }
+}
+
+/// Refreshes the directory monitoring.
+bool RefreshWatch(WatcherStructWin32* pWatch)
+{
+ return ReadDirectoryChangesW(
+ pWatch->Watch->DirHandle,
+ pWatch->Watch->mBuffer,
+ sizeof(pWatch->Watch->mBuffer),
+ pWatch->Watch->Recursive,
+ pWatch->Watch->NotifyFilter,
+ NULL,
+ &pWatch->Overlapped,
+ NULL
+ ) != 0;
+}
+
+/// Stops monitoring a directory.
+void DestroyWatch(WatcherStructWin32* pWatch)
+{
+ if (pWatch)
+ {
+ WatcherWin32 * tWatch = pWatch->Watch;
+
+ tWatch->StopNow = true;
+
+ CancelIo(tWatch->DirHandle);
+
+ RefreshWatch(pWatch);
+
+ if (!HasOverlappedIoCompleted(&pWatch->Overlapped))
+ {
+ SleepEx(5, TRUE);
+ }
+
+ CloseHandle(pWatch->Overlapped.hEvent);
+ CloseHandle(pWatch->Watch->DirHandle);
+ efSAFE_DELETE_ARRAY( pWatch->Watch->DirName );
+ efSAFE_DELETE( pWatch->Watch );
+ HeapFree(GetProcessHeap(), 0, pWatch);
+ }
+}
+
+/// Starts monitoring a directory.
+WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter)
+{
+ WatcherStructWin32 * tWatch;
+ size_t ptrsize = sizeof(*tWatch);
+ tWatch = static_cast<WatcherStructWin32*>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize));
+
+ WatcherWin32 * pWatch = new WatcherWin32();
+ tWatch->Watch = pWatch;
+
+ pWatch->DirHandle = CreateFileW(
+ szDirectory,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+ NULL
+ );
+
+ if (pWatch->DirHandle != INVALID_HANDLE_VALUE)
+ {
+ tWatch->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ pWatch->NotifyFilter = NotifyFilter;
+ pWatch->Recursive = recursive;
+
+ if (RefreshWatch(tWatch))
+ {
+ return tWatch;
+ }
+ else
+ {
+ CloseHandle(tWatch->Overlapped.hEvent);
+ CloseHandle(pWatch->DirHandle);
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, tWatch);
+ return NULL;
+}
+
+}
+
+ #endif
diff --git a/dep/efsw/src/efsw/WatcherWin32.hpp b/dep/efsw/src/efsw/WatcherWin32.hpp
new file mode 100644
index 00000000000..3c6d988fbf4
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherWin32.hpp
@@ -0,0 +1,77 @@
+#ifndef EFSW_WATCHERWIN32_HPP
+#define EFSW_WATCHERWIN32_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/FileInfo.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#include <windows.h>
+
+#ifdef EFSW_COMPILER_MSVC
+ #pragma comment(lib, "comctl32.lib")
+ #pragma comment(lib, "user32.lib")
+ #pragma comment(lib, "ole32.lib")
+
+ // disable secure warnings
+ #pragma warning (disable: 4996)
+#endif
+
+namespace efsw
+{
+
+class WatcherWin32;
+
+/// Internal watch data
+struct WatcherStructWin32
+{
+ OVERLAPPED Overlapped;
+ WatcherWin32 * Watch;
+};
+
+class cLastModifiedEvent
+{
+ public:
+ cLastModifiedEvent() {}
+ FileInfo file;
+ std::string fileName;
+};
+
+bool RefreshWatch(WatcherStructWin32* pWatch);
+
+void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped);
+
+void DestroyWatch(WatcherStructWin32* pWatch);
+
+WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter);
+
+class WatcherWin32 : public Watcher
+{
+ public:
+ WatcherWin32() :
+ Struct( NULL ),
+ DirHandle( NULL ),
+ lParam( 0 ),
+ NotifyFilter( 0 ),
+ StopNow( false ),
+ Watch( NULL ),
+ DirName( NULL )
+ {
+ }
+
+ WatcherStructWin32 * Struct;
+ HANDLE DirHandle;
+ BYTE mBuffer[63 * 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched is on the network! (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx)
+ LPARAM lParam;
+ DWORD NotifyFilter;
+ bool StopNow;
+ FileWatcherImpl* Watch;
+ char* DirName;
+ cLastModifiedEvent LastModifiedEvent;
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/base.hpp b/dep/efsw/src/efsw/base.hpp
new file mode 100644
index 00000000000..26108c76985
--- /dev/null
+++ b/dep/efsw/src/efsw/base.hpp
@@ -0,0 +1,110 @@
+#ifndef EFSW_BASE
+#define EFSW_BASE
+
+#include <efsw/sophist.h>
+#include <efsw/efsw.hpp>
+
+namespace efsw {
+
+typedef SOPHIST_int8 Int8;
+typedef SOPHIST_uint8 Uint8;
+typedef SOPHIST_int16 Int16;
+typedef SOPHIST_uint16 Uint16;
+typedef SOPHIST_int32 Int32;
+typedef SOPHIST_uint32 Uint32;
+typedef SOPHIST_int64 Int64;
+typedef SOPHIST_uint64 Uint64;
+
+#define EFSW_OS_WIN 1
+#define EFSW_OS_LINUX 2
+#define EFSW_OS_MACOSX 3
+#define EFSW_OS_BSD 4
+#define EFSW_OS_SOLARIS 5
+#define EFSW_OS_HAIKU 6
+#define EFSW_OS_ANDROID 7
+#define EFSW_OS_IOS 8
+
+#define EFSW_PLATFORM_WIN32 1
+#define EFSW_PLATFORM_INOTIFY 2
+#define EFSW_PLATFORM_KQUEUE 3
+#define EFSW_PLATFORM_FSEVENTS 4
+#define EFSW_PLATFORM_GENERIC 5
+
+#if defined(_WIN32)
+ /// Any Windows platform
+ #define EFSW_OS EFSW_OS_WIN
+ #define EFSW_PLATFORM EFSW_PLATFORM_WIN32
+
+ #if ( defined( _MSCVER ) || defined( _MSC_VER ) )
+ #define EFSW_COMPILER_MSVC
+ #endif
+
+#elif defined( __FreeBSD__ ) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined( __DragonFly__ )
+ #define EFSW_OS EFSW_OS_BSD
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+
+#elif defined( __APPLE_CC__ ) || defined ( __APPLE__ )
+ #include <TargetConditionals.h>
+
+ #if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR )
+ #define EFSW_OS EFSW_OS_IOS
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+ #else
+ #define EFSW_OS EFSW_OS_MACOSX
+
+ #if defined(EFSW_FSEVENTS_NOT_SUPPORTED)
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+ #else
+ #define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS
+ #endif
+ #endif
+
+#elif defined(__linux__)
+ /// This includes Linux and Android
+ #ifndef EFSW_KQUEUE
+ #define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY
+ #else
+ /// This is for testing libkqueue, sadly it doesnt work
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+ #endif
+
+ #if defined( __ANDROID__ ) || defined( ANDROID )
+ #define EFSW_OS EFSW_OS_ANDROID
+ #else
+ #define EFSW_OS EFSW_OS_LINUX
+ #endif
+
+#else
+ #if defined( __SVR4 )
+ #define EFSW_OS EFSW_OS_SOLARIS
+ #elif defined( __HAIKU__ ) || defined( __BEOS__ )
+ #define EFSW_OS EFSW_OS_HAIKU
+ #endif
+
+ /// Everything else
+ #define EFSW_PLATFORM EFSW_PLATFORM_GENERIC
+#endif
+
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ #define EFSW_PLATFORM_POSIX
+#endif
+
+#if 1 == SOPHIST_pointer64
+ #define EFSW_64BIT
+#else
+ #define EFSW_32BIT
+#endif
+
+#if defined(arm) || defined(__arm__)
+ #define EFSW_ARM
+#endif
+
+#define efCOMMA ,
+
+#define efSAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define efSAFE_DELETE_ARRAY(p) { if(p) { delete [] (p); (p)=NULL; } }
+#define efARRAY_SIZE(__array) ( sizeof(__array) / sizeof(__array[0]) )
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/inotify-nosys.h b/dep/efsw/src/efsw/inotify-nosys.h
new file mode 100644
index 00000000000..75df5d3ced3
--- /dev/null
+++ b/dep/efsw/src/efsw/inotify-nosys.h
@@ -0,0 +1,159 @@
+#ifndef _LINUX_INOTIFY_H
+#define _LINUX_INOTIFY_H
+
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*
+ * struct inotify_event - structure read from the inotify device for each event
+ *
+ * When you are watching a directory, you will receive the filename for events
+ * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
+ */
+struct inotify_event {
+ int wd; /* watch descriptor */
+ uint32_t mask; /* watch mask */
+ uint32_t cookie; /* cookie to synchronize two events */
+ uint32_t len; /* length (including nulls) of name */
+ char name __flexarr; /* stub for possible name */
+};
+
+/* the following are legal, implemented events that user-space can watch for */
+#define IN_ACCESS 0x00000001 /* File was accessed */
+#define IN_MODIFY 0x00000002 /* File was modified */
+#define IN_ATTRIB 0x00000004 /* Metadata changed */
+#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
+#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
+#define IN_OPEN 0x00000020 /* File was opened */
+#define IN_MOVED_FROM 0x00000040 /* File was moved from X */
+#define IN_MOVED_TO 0x00000080 /* File was moved to Y */
+#define IN_CREATE 0x00000100 /* Subfile was created */
+#define IN_DELETE 0x00000200 /* Subfile was deleted */
+#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
+#define IN_MOVE_SELF 0x00000800 /* Self was moved */
+
+/* the following are legal events. they are sent as needed to any watch */
+#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */
+#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
+#define IN_IGNORED 0x00008000 /* File was ignored */
+
+/* helper events */
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
+
+/* special flags */
+#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
+#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
+#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
+#define IN_ISDIR 0x40000000 /* event occurred against dir */
+#define IN_ONESHOT 0x80000000 /* only send event once */
+
+/*
+ * All of the events - we build the list by hand so that we can add flags in
+ * the future and not break backward compatibility. Apps will get only the
+ * events that they originally wanted. Be sure to add new events here!
+ */
+#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
+ IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
+ IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \
+ IN_MOVE_SELF)
+
+#if defined (__alpha__)
+# define __NR_inotify_init 444
+# define __NR_inotify_add_watch 445
+# define __NR_inotify_rm_watch 446
+
+#elif defined (__arm__)
+# define __NR_inotify_init (__NR_SYSCALL_BASE+316)
+# define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317)
+# define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318)
+
+#elif defined (__frv__)
+# define __NR_inotify_init 291
+# define __NR_inotify_add_watch 292
+# define __NR_inotify_rm_watch 293
+
+#elif defined(__i386__)
+# define __NR_inotify_init 291
+# define __NR_inotify_add_watch 292
+# define __NR_inotify_rm_watch 293
+
+#elif defined (__ia64__)
+# define __NR_inotify_init 1277
+# define __NR_inotify_add_watch 1278
+# define __NR_inotify_rm_watch 1279
+
+#elif defined (__mips__)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_inotify_init (__NR_Linux + 284)
+# define __NR_inotify_add_watch (__NR_Linux + 285)
+# define __NR_inotify_rm_watch (__NR_Linux + 286)
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_inotify_init (__NR_Linux + 243)
+# define __NR_inotify_add_watch (__NR_Linux + 243)
+# define __NR_inotify_rm_watch (__NR_Linux + 243)
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_inotify_init (__NR_Linux + 247)
+# define __NR_inotify_add_watch (__NR_Linux + 248)
+# define __NR_inotify_rm_watch (__NR_Linux + 249)
+# endif
+
+#elif defined(__parisc__)
+# define __NR_inotify_init (__NR_Linux + 269)
+# define __NR_inotify_add_watch (__NR_Linux + 270)
+# define __NR_inotify_rm_watch (__NR_Linux + 271)
+
+#elif defined(__powerpc__) || defined(__powerpc64__)
+# define __NR_inotify_init 275
+# define __NR_inotify_add_watch 276
+# define __NR_inotify_rm_watch 277
+
+#elif defined (__s390__)
+# define __NR_inotify_init 284
+# define __NR_inotify_add_watch 285
+# define __NR_inotify_rm_watch 286
+
+#elif defined (__sh__)
+# define __NR_inotify_init 290
+# define __NR_inotify_add_watch 291
+# define __NR_inotify_rm_watch 292
+
+#elif defined (__sh64__)
+# define __NR_inotify_init 318
+# define __NR_inotify_add_watch 319
+# define __NR_inotify_rm_watch 320
+
+#elif defined (__sparc__) || defined (__sparc64__)
+# define __NR_inotify_init 151
+# define __NR_inotify_add_watch 152
+# define __NR_inotify_rm_watch 156
+
+#elif defined(__x86_64__)
+# define __NR_inotify_init 253
+# define __NR_inotify_add_watch 254
+# define __NR_inotify_rm_watch 255
+
+#else
+# error "Unsupported architecture!"
+#endif
+
+static inline int inotify_init (void)
+{
+ return syscall (__NR_inotify_init);
+}
+
+static inline int inotify_add_watch (int fd, const char *name, uint32_t mask)
+{
+ return syscall (__NR_inotify_add_watch, fd, name, mask);
+}
+
+static inline int inotify_rm_watch (int fd, uint32_t wd)
+{
+ return syscall (__NR_inotify_rm_watch, fd, wd);
+}
+
+
+#endif /* _LINUX_INOTIFY_H */
diff --git a/dep/efsw/src/efsw/platform/platformimpl.hpp b/dep/efsw/src/efsw/platform/platformimpl.hpp
new file mode 100644
index 00000000000..86a74eee0c8
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/platformimpl.hpp
@@ -0,0 +1,20 @@
+#ifndef EFSW_PLATFORMIMPL_HPP
+#define EFSW_PLATFORMIMPL_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+ #include <efsw/platform/posix/ThreadImpl.hpp>
+ #include <efsw/platform/posix/MutexImpl.hpp>
+ #include <efsw/platform/posix/SystemImpl.hpp>
+ #include <efsw/platform/posix/FileSystemImpl.hpp>
+#elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+ #include <efsw/platform/win/ThreadImpl.hpp>
+ #include <efsw/platform/win/MutexImpl.hpp>
+ #include <efsw/platform/win/SystemImpl.hpp>
+ #include <efsw/platform/win/FileSystemImpl.hpp>
+#else
+ #error Thread, Mutex, and System not implemented for this platform.
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp
new file mode 100644
index 00000000000..e061b25d56b
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp
@@ -0,0 +1,144 @@
+#include <efsw/platform/posix/FileSystemImpl.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <efsw/FileInfo.hpp>
+#include <efsw/FileSystem.hpp>
+#include <dirent.h>
+#include <cstring>
+
+#ifndef _DARWIN_FEATURE_64_BIT_INODE
+#define _DARWIN_FEATURE_64_BIT_INODE
+#endif
+
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#include <sys/stat.h>
+#include <cstdlib>
+
+#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID
+#include <sys/vfs.h>
+#elif EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_IOS
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+/** Remote file systems codes */
+#define S_MAGIC_AFS 0x5346414F
+#define S_MAGIC_AUFS 0x61756673
+#define S_MAGIC_CEPH 0x00C36400
+#define S_MAGIC_CIFS 0xFF534D42
+#define S_MAGIC_CODA 0x73757245
+#define S_MAGIC_FHGFS 0x19830326
+#define S_MAGIC_FUSEBLK 0x65735546
+#define S_MAGIC_FUSECTL 0x65735543
+#define S_MAGIC_GFS 0x01161970
+#define S_MAGIC_GPFS 0x47504653
+#define S_MAGIC_KAFS 0x6B414653
+#define S_MAGIC_LUSTRE 0x0BD00BD0
+#define S_MAGIC_NCP 0x564C
+#define S_MAGIC_NFS 0x6969
+#define S_MAGIC_NFSD 0x6E667364
+#define S_MAGIC_OCFS2 0x7461636F
+#define S_MAGIC_PANFS 0xAAD7AAEA
+#define S_MAGIC_PIPEFS 0x50495045
+#define S_MAGIC_SMB 0x517B
+#define S_MAGIC_SNFS 0xBEEFDEAD
+#define S_MAGIC_VMHGFS 0xBACBACBC
+#define S_MAGIC_VXFS 0xA501FCF5
+
+namespace efsw { namespace Platform {
+
+FileInfoMap FileSystem::filesInfoFromPath( const std::string& path )
+{
+ FileInfoMap files;
+
+ DIR *dp;
+ struct dirent *dirp;
+
+ if( ( dp = opendir( path.c_str() ) ) == NULL)
+ return files;
+
+ while ( ( dirp = readdir(dp) ) != NULL)
+ {
+ if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 )
+ {
+ std::string name( dirp->d_name );
+ std::string fpath( path + name );
+
+ files[ name ] = FileInfo( fpath );
+ }
+ }
+
+ closedir(dp);
+
+ return files;
+}
+
+char FileSystem::getOSSlash()
+{
+ return '/';
+}
+
+bool FileSystem::isDirectory( const std::string& path )
+{
+ struct stat st;
+ int res = stat( path.c_str(), &st );
+
+ if ( 0 == res )
+ {
+ return static_cast<bool>( S_ISDIR(st.st_mode) );
+ }
+
+ return false;
+}
+
+bool FileSystem::isRemoteFS( const std::string& directory )
+{
+#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID || EFSW_OS == EFSW_OS_IOS
+ struct statfs statfsbuf;
+
+ statfs( directory.c_str(), &statfsbuf );
+
+ switch ( statfsbuf.f_type | 0UL )
+ {
+ case S_MAGIC_AFS: /* 0x5346414F remote */
+ case S_MAGIC_AUFS: /* 0x61756673 remote */
+ case S_MAGIC_CEPH: /* 0x00C36400 remote */
+ case S_MAGIC_CIFS: /* 0xFF534D42 remote */
+ case S_MAGIC_CODA: /* 0x73757245 remote */
+ case S_MAGIC_FHGFS: /* 0x19830326 remote */
+ case S_MAGIC_FUSEBLK: /* 0x65735546 remote */
+ case S_MAGIC_FUSECTL: /* 0x65735543 remote */
+ case S_MAGIC_GFS: /* 0x01161970 remote */
+ case S_MAGIC_GPFS: /* 0x47504653 remote */
+ case S_MAGIC_KAFS: /* 0x6B414653 remote */
+ case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
+ case S_MAGIC_NCP: /* 0x564C remote */
+ case S_MAGIC_NFS: /* 0x6969 remote */
+ case S_MAGIC_NFSD: /* 0x6E667364 remote */
+ case S_MAGIC_OCFS2: /* 0x7461636F remote */
+ case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */
+ case S_MAGIC_PIPEFS: /* 0x50495045 remote */
+ case S_MAGIC_SMB: /* 0x517B remote */
+ case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */
+ case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */
+ case S_MAGIC_VXFS: /* 0xA501FCF5 remote */
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+#endif
+
+ return false;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp
new file mode 100644
index 00000000000..865b3f8dfdf
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp
@@ -0,0 +1,27 @@
+#ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP
+#define EFSW_FILESYSTEMIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/FileInfo.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+namespace efsw { namespace Platform {
+
+class FileSystem
+{
+ public:
+ static FileInfoMap filesInfoFromPath( const std::string& path );
+
+ static char getOSSlash();
+
+ static bool isDirectory( const std::string& path );
+
+ static bool isRemoteFS( const std::string& directory );
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp b/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp
new file mode 100644
index 00000000000..6f2af5abc61
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp
@@ -0,0 +1,32 @@
+#include <efsw/platform/posix/MutexImpl.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+namespace efsw { namespace Platform {
+
+MutexImpl::MutexImpl()
+{
+ pthread_mutexattr_t attributes;
+ pthread_mutexattr_init(&attributes);
+ pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mMutex, &attributes);
+}
+
+MutexImpl::~MutexImpl()
+{
+ pthread_mutex_destroy(&mMutex);
+}
+
+void MutexImpl::lock()
+{
+ pthread_mutex_lock(&mMutex);
+}
+
+void MutexImpl::unlock()
+{
+ pthread_mutex_unlock(&mMutex);
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp b/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp
new file mode 100644
index 00000000000..d51eecb16aa
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp
@@ -0,0 +1,31 @@
+#ifndef EFSW_MUTEXIMPLPOSIX_HPP
+#define EFSW_MUTEXIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <pthread.h>
+
+namespace efsw { namespace Platform {
+
+class MutexImpl
+{
+ public:
+ MutexImpl();
+
+ ~MutexImpl();
+
+ void lock();
+
+ void unlock();
+ private:
+ pthread_mutex_t mMutex;
+};
+
+}}
+
+#endif
+
+#endif
+
diff --git a/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp b/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp
new file mode 100644
index 00000000000..22e37095afd
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp
@@ -0,0 +1,180 @@
+#include <efsw/platform/posix/SystemImpl.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <cstdio>
+#include <pthread.h>
+#include <sys/time.h>
+#include <limits.h>
+#include <sys/resource.h>
+
+#include <efsw/FileSystem.hpp>
+#include <efsw/Debug.hpp>
+
+#if EFSW_OS == EFSW_OS_MACOSX
+ #include <CoreFoundation/CoreFoundation.h>
+#elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID
+ #include <libgen.h>
+ #include <unistd.h>
+#elif EFSW_OS == EFSW_OS_HAIKU
+ #include <kernel/OS.h>
+ #include <kernel/image.h>
+#elif EFSW_OS == EFSW_OS_SOLARIS
+ #include <stdlib.h>
+#elif EFSW_OS == EFSW_OS_BSD
+ #include <sys/sysctl.h>
+#endif
+
+namespace efsw { namespace Platform {
+
+void System::sleep( const unsigned long& ms )
+{
+ // usleep( static_cast<unsigned long>( ms * 1000 ) );
+
+ // usleep is not reliable enough (it might block the
+ // whole process instead of just the current thread)
+ // so we must use pthread_cond_timedwait instead
+
+ // this implementation is inspired from Qt
+ // and taken from SFML
+
+ unsigned long long usecs = ms * 1000;
+
+ // get the current time
+ timeval tv;
+ gettimeofday(&tv, NULL);
+
+ // construct the time limit (current time + time to wait)
+ timespec ti;
+ ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
+ ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
+ ti.tv_nsec %= 1000000000;
+
+ // create a mutex and thread condition
+ pthread_mutex_t mutex;
+ pthread_mutex_init(&mutex, 0);
+ pthread_cond_t condition;
+ pthread_cond_init(&condition, 0);
+
+ // wait...
+ pthread_mutex_lock(&mutex);
+ pthread_cond_timedwait(&condition, &mutex, &ti);
+ pthread_mutex_unlock(&mutex);
+
+ // destroy the mutex and condition
+ pthread_cond_destroy(&condition);
+}
+
+std::string System::getProcessPath()
+{
+#if EFSW_OS == EFSW_OS_MACOSX
+ char exe_file[FILENAME_MAX + 1];
+
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+
+ if (mainBundle)
+ {
+ CFURLRef mainURL = CFBundleCopyBundleURL(mainBundle);
+
+ if (mainURL)
+ {
+ int ok = CFURLGetFileSystemRepresentation ( mainURL, (Boolean) true, (UInt8*)exe_file, FILENAME_MAX );
+
+ if (ok)
+ {
+ return std::string(exe_file) + "/";
+ }
+ }
+ }
+
+ return "./";
+#elif EFSW_OS == EFSW_OS_LINUX
+ char exe_file[FILENAME_MAX + 1];
+
+ int size;
+
+ size = readlink("/proc/self/exe", exe_file, FILENAME_MAX);
+
+ if (size < 0)
+ {
+ return std::string( "./" );
+ }
+ else
+ {
+ exe_file[size] = '\0';
+ return std::string( dirname( exe_file ) ) + "/";
+ }
+
+#elif EFSW_OS == EFSW_OS_BSD
+ int mib[4];
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+ char buf[1024];
+ size_t cb = sizeof(buf);
+ sysctl(mib, 4, buf, &cb, NULL, 0);
+
+ return FileSystem::pathRemoveFileName( std::string( buf ) );
+
+#elif EFSW_OS == EFSW_OS_SOLARIS
+ return FileSystem::pathRemoveFileName( std::string( getexecname() ) );
+
+#elif EFSW_OS == EFSW_OS_HAIKU
+ image_info info;
+ int32 cookie = 0;
+
+ while ( B_OK == get_next_image_info( 0, &cookie, &info ) )
+ {
+ if ( info.type == B_APP_IMAGE )
+ break;
+ }
+
+ return FileSystem::pathRemoveFileName( std::string( info.name ) );
+
+#elif EFSW_OS == EFSW_OS_ANDROID
+ return "/sdcard/";
+
+#else
+ #warning getProcessPath() not implemented on this platform. ( will return "./" )
+ return "./";
+
+#endif
+}
+
+void System::maxFD()
+{
+ static bool maxed = false;
+
+ if ( !maxed )
+ {
+ struct rlimit limit;
+ getrlimit( RLIMIT_NOFILE, &limit );
+ limit.rlim_cur = limit.rlim_max;
+ setrlimit( RLIMIT_NOFILE, &limit );
+
+ getrlimit( RLIMIT_NOFILE, &limit );
+
+ efDEBUG( "File descriptor limit %ld\n", limit.rlim_cur );
+
+ maxed = true;
+ }
+}
+
+Uint64 System::getMaxFD()
+{
+ static rlim_t max_fd = 0;
+
+ if ( max_fd == 0 )
+ {
+ struct rlimit limit;
+ getrlimit( RLIMIT_NOFILE, &limit );
+ max_fd = limit.rlim_cur;
+ }
+
+ return max_fd;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp b/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp
new file mode 100644
index 00000000000..34734104467
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp
@@ -0,0 +1,26 @@
+#ifndef EFSW_SYSTEMIMPLPOSIX_HPP
+#define EFSW_SYSTEMIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+namespace efsw { namespace Platform {
+
+class System
+{
+ public:
+ static void sleep( const unsigned long& ms );
+
+ static std::string getProcessPath();
+
+ static void maxFD();
+
+ static Uint64 getMaxFD();
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp b/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp
new file mode 100644
index 00000000000..2d3671db9b8
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp
@@ -0,0 +1,68 @@
+#include <efsw/platform/posix/ThreadImpl.hpp>
+#include <efsw/Thread.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <cassert>
+#include <iostream>
+#include <efsw/Debug.hpp>
+
+namespace efsw { namespace Platform {
+
+ThreadImpl::ThreadImpl( Thread * owner ) :
+ mIsActive(false)
+{
+ mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0;
+
+ if ( !mIsActive )
+ {
+ efDEBUG( "Failed to create thread\n" );
+ }
+}
+
+void ThreadImpl::wait()
+{
+ // Wait for the thread to finish, no timeout
+ if ( mIsActive )
+ {
+ assert( pthread_equal( pthread_self(), mThread ) == 0 );
+
+ pthread_join( mThread, NULL );
+
+ mIsActive = false; // Reset the thread state
+ }
+}
+
+void ThreadImpl::terminate()
+{
+ if ( mIsActive )
+ {
+ #if !defined( __ANDROID__ ) && !defined( ANDROID )
+ pthread_cancel( mThread );
+ #else
+ pthread_kill( mThread , SIGUSR1 );
+ #endif
+
+ mIsActive = false;
+ }
+}
+
+void * ThreadImpl::entryPoint( void * userData )
+{
+ // The Thread instance is stored in the user data
+ Thread * owner = static_cast<Thread*>( userData );
+
+ // Tell the thread to handle cancel requests immediatly
+ #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
+ pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
+ #endif
+
+ // Forward to the owner
+ owner->run();
+
+ return NULL;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp b/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp
new file mode 100644
index 00000000000..be6dc1b3e58
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp
@@ -0,0 +1,35 @@
+#ifndef EFSW_THREADIMPLPOSIX_HPP
+#define EFSW_THREADIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <pthread.h>
+
+namespace efsw {
+
+class Thread;
+
+namespace Platform {
+
+class ThreadImpl
+{
+ public:
+ ThreadImpl( Thread * owner );
+
+ void wait();
+
+ void terminate();
+ protected:
+ static void * entryPoint( void* userData );
+
+ pthread_t mThread;
+ bool mIsActive;
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp b/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp
new file mode 100644
index 00000000000..376a474e662
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp
@@ -0,0 +1,89 @@
+#include <efsw/platform/win/FileSystemImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#ifndef EFSW_COMPILER_MSVC
+#include <dirent.h>
+#endif
+
+namespace efsw { namespace Platform {
+
+FileInfoMap FileSystem::filesInfoFromPath( const std::string& path )
+{
+ FileInfoMap files;
+
+ String tpath( path );
+
+ if ( tpath[ tpath.size() - 1 ] == '/' || tpath[ tpath.size() - 1 ] == '\\' )
+ {
+ tpath += "*";
+ }
+ else
+ {
+ tpath += "\\*";
+ }
+
+ WIN32_FIND_DATAW findFileData;
+ HANDLE hFind = FindFirstFileW( (LPCWSTR)tpath.toWideString().c_str(), &findFileData );
+
+ if( hFind != INVALID_HANDLE_VALUE )
+ {
+ std::string name( String( findFileData.cFileName ).toUtf8() );
+ std::string fpath( path + name );
+
+ if ( name != "." && name != ".." )
+ {
+ files[ name ] = FileInfo( fpath );
+ }
+
+ while( FindNextFileW( hFind, &findFileData ) )
+ {
+ name = String( findFileData.cFileName ).toUtf8();
+ fpath = path + name;
+
+ if ( name != "." && name != ".." )
+ {
+ files[ name ] = FileInfo( fpath );
+ }
+ }
+
+ FindClose( hFind );
+ }
+
+ return files;
+}
+
+char FileSystem::getOSSlash()
+{
+ return '\\';
+}
+
+bool FileSystem::isDirectory( const std::string& path )
+{
+ return 0 != ( GetFileAttributesW( String( path ).toWideString().c_str() ) & FILE_ATTRIBUTE_DIRECTORY );
+}
+
+bool FileSystem::isRemoteFS( const std::string& directory )
+{
+ if ((directory[0] == '\\' || directory[0] == '/') &&
+ (directory[1] == '\\' || directory[1] == '/'))
+ {
+ return true;
+ }
+
+ if ( directory.size() >= 3 )
+ {
+ return 4 == GetDriveTypeA( directory.substr( 0, 3 ).c_str() );
+ }
+
+ return false;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp b/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp
new file mode 100644
index 00000000000..597edc4a647
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp
@@ -0,0 +1,28 @@
+#ifndef EFSW_FILESYSTEMIMPLWIN_HPP
+#define EFSW_FILESYSTEMIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/String.hpp>
+#include <efsw/FileInfo.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw { namespace Platform {
+
+class FileSystem
+{
+ public:
+ static FileInfoMap filesInfoFromPath( const std::string& path );
+
+ static char getOSSlash();
+
+ static bool isDirectory( const std::string& path );
+
+ static bool isRemoteFS( const std::string& directory );
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/MutexImpl.cpp b/dep/efsw/src/efsw/platform/win/MutexImpl.cpp
new file mode 100644
index 00000000000..0c8c36d8b39
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/MutexImpl.cpp
@@ -0,0 +1,29 @@
+#include <efsw/platform/win/MutexImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw { namespace Platform {
+
+MutexImpl::MutexImpl()
+{
+ InitializeCriticalSection(&mMutex);
+}
+
+MutexImpl::~MutexImpl()
+{
+ DeleteCriticalSection(&mMutex);
+}
+
+void MutexImpl::lock()
+{
+ EnterCriticalSection(&mMutex);
+}
+
+void MutexImpl::unlock()
+{
+ LeaveCriticalSection(&mMutex);
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/MutexImpl.hpp b/dep/efsw/src/efsw/platform/win/MutexImpl.hpp
new file mode 100644
index 00000000000..da1e20c5fa9
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/MutexImpl.hpp
@@ -0,0 +1,34 @@
+#ifndef EFSW_MUTEXIMPLWIN_HPP
+#define EFSW_MUTEXIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+namespace efsw { namespace Platform {
+
+class MutexImpl
+{
+ public:
+ MutexImpl();
+
+ ~MutexImpl();
+
+ void lock();
+
+ void unlock();
+ private:
+ CRITICAL_SECTION mMutex;
+};
+
+}}
+
+#endif
+
+#endif
+
diff --git a/dep/efsw/src/efsw/platform/win/SystemImpl.cpp b/dep/efsw/src/efsw/platform/win/SystemImpl.cpp
new file mode 100644
index 00000000000..ddbe1e5c45c
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/SystemImpl.cpp
@@ -0,0 +1,50 @@
+#include <efsw/platform/win/SystemImpl.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <cstdlib>
+
+namespace efsw { namespace Platform {
+
+void System::sleep( const unsigned long& ms )
+{
+ ::Sleep( ms );
+}
+
+std::string System::getProcessPath()
+{
+ // Get path to executable:
+ WCHAR szDrive[_MAX_DRIVE];
+ WCHAR szDir[_MAX_DIR];
+ WCHAR szFilename[_MAX_DIR];
+ WCHAR szExt[_MAX_DIR];
+ std::wstring dllName( _MAX_DIR, 0 );
+
+ GetModuleFileNameW(0, &dllName[0], _MAX_PATH);
+
+ #ifdef EFSW_COMPILER_MSVC
+ _wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt, _MAX_DIR );
+ #else
+ _wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt);
+ #endif
+
+ return String( szDrive ).toUtf8() + String( szDir ).toUtf8();
+}
+
+void System::maxFD()
+{
+}
+
+Uint64 System::getMaxFD()
+{ // Number of ReadDirectory per thread
+ return 60;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/SystemImpl.hpp b/dep/efsw/src/efsw/platform/win/SystemImpl.hpp
new file mode 100644
index 00000000000..2f785e3565c
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/SystemImpl.hpp
@@ -0,0 +1,26 @@
+#ifndef EFSW_SYSTEMIMPLWIN_HPP
+#define EFSW_SYSTEMIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw { namespace Platform {
+
+class System
+{
+ public:
+ static void sleep( const unsigned long& ms );
+
+ static std::string getProcessPath();
+
+ static void maxFD();
+
+ static Uint64 getMaxFD();
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp b/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp
new file mode 100644
index 00000000000..2fa30f30060
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp
@@ -0,0 +1,56 @@
+#include <efsw/platform/win/ThreadImpl.hpp>
+#include <efsw/Thread.hpp>
+#include <assert.h>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#include <efsw/Debug.hpp>
+
+namespace efsw { namespace Platform {
+
+ThreadImpl::ThreadImpl( Thread *owner )
+{
+ mThread = reinterpret_cast<HANDLE>( _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) );
+
+ if ( !mThread )
+ {
+ efDEBUG( "Failed to create thread\n" );
+ }
+}
+
+void ThreadImpl::wait()
+{
+ // Wait for the thread to finish, no timeout
+ if ( mThread )
+ {
+ assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself!
+
+ WaitForSingleObject( mThread, INFINITE );
+ }
+}
+
+void ThreadImpl::terminate()
+{
+ if ( mThread )
+ {
+ TerminateThread( mThread, 0 );
+ }
+}
+
+unsigned int __stdcall ThreadImpl::entryPoint( void * userData )
+{
+ // The Thread instance is stored in the user data
+ Thread * owner = static_cast<Thread*>( userData );
+
+ // Forward to the owner
+ owner->run();
+
+ // Optional, but it is cleaner
+ _endthreadex(0);
+
+ return 0;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp b/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp
new file mode 100644
index 00000000000..506c659c675
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp
@@ -0,0 +1,39 @@
+#ifndef EFSW_THREADIMPLWIN_HPP
+#define EFSW_THREADIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <process.h>
+
+namespace efsw {
+
+class Thread;
+
+namespace Platform {
+
+class ThreadImpl
+{
+ public:
+ ThreadImpl( Thread * owner );
+
+ void wait();
+
+ void terminate();
+ protected:
+ static unsigned int __stdcall entryPoint(void* userData);
+
+ HANDLE mThread;
+ unsigned int mThreadId;
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/sophist.h b/dep/efsw/src/efsw/sophist.h
new file mode 100644
index 00000000000..3a645040e2f
--- /dev/null
+++ b/dep/efsw/src/efsw/sophist.h
@@ -0,0 +1,147 @@
+/* sophist.h - 0.3 - public domain - Sean Barrett 2010
+** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net
+** Sophist provides portable types; you typedef/#define them to your own names
+**
+** defines:
+** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian
+** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined
+** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit
+**
+** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer
+** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16
+** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64
+** - SOPHIST_int64_constant(number) - macros for creating 64-bit
+** - SOPHIST_uint64_constant(number) integer constants
+** - SOPHIST_printf_format64 - string for printf format for int64
+*/
+
+#ifndef __INCLUDE_SOPHIST_H__
+#define __INCLUDE_SOPHIST_H__
+
+#define SOPHIST_compiletime_assert(name,val) \
+ typedef int SOPHIST__assert##name[(val) ? 1 : -1]
+
+/* define a couple synthetic rules to make code more readable */
+#if (defined(__sparc__) || defined(__sparc)) && \
+ (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__))
+ #define SOPHIST_sparc64
+#endif
+
+#if (defined(linux) || defined(__linux__)) && \
+ (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64))
+ #define SOPHIST_linux64
+#endif
+
+/* basic types */
+typedef signed char SOPHIST_int8;
+typedef unsigned char SOPHIST_uint8;
+
+typedef signed short SOPHIST_int16;
+typedef unsigned short SOPHIST_uint16;
+
+#ifdef __palmos__
+ typedef signed long SOPHIST_int32;
+ typedef unsigned long SOPHIST_uint32;
+#else
+ typedef signed int SOPHIST_int32;
+ typedef unsigned int SOPHIST_uint32;
+#endif
+
+#ifndef SOPHIST_NO_64
+ #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \
+ || (defined(__alpha) && defined(__DECC))
+
+ typedef signed __int64 SOPHIST_int64;
+ typedef unsigned __int64 SOPHIST_uint64;
+ #define SOPHIST_has_64 1
+ #define SOPHIST_int64_constant(x) (x##i64)
+ #define SOPHIST_uint64_constant(x) (x##ui64)
+ #define SOPHIST_printf_format64 "I64"
+
+ #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64)
+
+ typedef signed long SOPHIST_int64;
+ typedef unsigned long SOPHIST_uint64;
+
+ #define SOPHIST_has_64 1
+ #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x)
+ #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x)
+ #define SOPHIST_printf_format64 "l"
+
+ #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \
+ || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \
+ || defined(sgi) || defined (__sgi) || defined(__sgi__) \
+ || defined(_CRAYC)
+
+ typedef signed long long SOPHIST_int64;
+ typedef unsigned long long SOPHIST_uint64;
+
+ #define SOPHIST_has_64 1
+ #define SOPHIST_int64_constant(x) (x##LL)
+ #define SOPHIST_uint64_constant(x) (x##ULL)
+ #define SOPHIST_printf_format64 "ll"
+ #endif
+#endif
+
+#ifndef SOPHIST_has_64
+#define SOPHIST_has_64 0
+#endif
+
+SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1);
+SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2);
+SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4);
+SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4);
+
+#if SOPHIST_has_64
+ SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8);
+ SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8);
+#endif
+
+/* determine whether pointers are 64-bit */
+
+#if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \
+ || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \
+ || defined(__64BIT__) \
+ || defined(__LP64) || defined(__LP64__) || defined(_LP64) \
+ || defined(_ADDR64) || defined(_CRAYC) \
+
+ #define SOPHIST_pointer64 1
+
+ SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8);
+
+ typedef SOPHIST_int64 SOPHIST_intptr;
+ typedef SOPHIST_uint64 SOPHIST_uintptr;
+#else
+
+ #define SOPHIST_pointer64 0
+
+ SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4);
+
+ /* do we care about pointers that are only 16-bit? */
+ typedef SOPHIST_int32 SOPHIST_intptr;
+ typedef SOPHIST_uint32 SOPHIST_uintptr;
+
+#endif
+
+SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *));
+
+/* enumerate known little endian cases; fallback to big-endian */
+
+#define SOPHIST_little_endian 1
+#define SOPHIST_big_endian 2
+
+#if defined(__386__) || defined(i386) || defined(__i386__) \
+ || defined(__X86) || defined(_M_IX86) \
+ || defined(_M_X64) || defined(__x86_64__) \
+ || defined(alpha) || defined(__alpha) || defined(__alpha__) \
+ || defined(_M_ALPHA) \
+ || defined(ARM) || defined(_ARM) || defined(__arm__) \
+ || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
+ || defined(_WIN32_WCE) || defined(__NT__) \
+ || defined(__MIPSEL__)
+ #define SOPHIST_endian SOPHIST_little_endian
+#else
+ #define SOPHIST_endian SOPHIST_big_endian
+#endif
+
+#endif /* __INCLUDE_SOPHIST_H__ */
diff --git a/dep/efsw/src/test/efsw-test.cpp b/dep/efsw/src/test/efsw-test.cpp
new file mode 100644
index 00000000000..a49e3414fcc
--- /dev/null
+++ b/dep/efsw/src/test/efsw-test.cpp
@@ -0,0 +1,151 @@
+#include <efsw/efsw.hpp>
+#include <efsw/System.hpp>
+#include <efsw/FileSystem.hpp>
+#include <signal.h>
+#include <iostream>
+
+bool STOP = false;
+
+void sigend(int signal)
+{
+ std::cout << std::endl << "Bye bye" << std::endl;
+ STOP = true;
+}
+
+/// Processes a file action
+class UpdateListener : public efsw::FileWatchListener
+{
+ public:
+ UpdateListener() {}
+
+ std::string getActionName( efsw::Action action )
+ {
+ switch ( action )
+ {
+ case efsw::Actions::Add: return "Add";
+ case efsw::Actions::Modified: return "Modified";
+ case efsw::Actions::Delete: return "Delete";
+ case efsw::Actions::Moved: return "Moved";
+ default: return "Bad Action";
+ }
+ }
+
+ void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" )
+ {
+ std::cout << "DIR (" << dir + ") FILE (" + ( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) + filename + ") has event " << getActionName( action ) << std::endl;
+ }
+};
+
+efsw::WatchID handleWatchID( efsw::WatchID watchid )
+{
+ switch ( watchid )
+ {
+ case efsw::Errors::FileNotFound:
+ case efsw::Errors::FileRepeated:
+ case efsw::Errors::FileOutOfScope:
+ case efsw::Errors::FileRemote:
+ case efsw::Errors::Unspecified:
+ {
+ std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl;
+ break;
+ }
+ default:
+ {
+ std::cout << "Added WatchID: " << watchid << std::endl;
+ }
+ }
+
+ return watchid;
+}
+
+int main(int argc, char **argv)
+{
+ signal( SIGABRT , sigend );
+ signal( SIGINT , sigend );
+ signal( SIGTERM , sigend );
+
+ std::cout << "Press ^C to exit demo" << std::endl;
+
+ bool commonTest = true;
+ bool useGeneric = false;
+ std::string path;
+
+ if ( argc >= 2 )
+ {
+ path = std::string( argv[1] );
+
+ if ( efsw::FileSystem::isDirectory( path ) )
+ {
+ commonTest = false;
+ }
+
+ if ( argc >= 3 )
+ {
+ if ( std::string( argv[2] ) == "true" )
+ {
+ useGeneric = true;
+ }
+ }
+ }
+
+ UpdateListener * ul = new UpdateListener();
+
+ /// create the file watcher object
+ efsw::FileWatcher fileWatcher( useGeneric );
+
+ fileWatcher.followSymlinks( false );
+ fileWatcher.allowOutOfScopeLinks( false );
+
+ if ( commonTest )
+ {
+ std::string CurPath( efsw::System::getProcessPath() );
+
+ std::cout << "CurPath: " << CurPath.c_str() << std::endl;
+
+ /// add a watch to the system
+ handleWatchID( fileWatcher.addWatch( CurPath + "test", ul, true ) );
+
+ /// starts watching
+ fileWatcher.watch();
+
+ /// adds another watch after started watching...
+ efsw::System::sleep( 100 );
+
+ efsw::WatchID watchID = handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) );
+
+ /// delete the watch
+ if ( watchID > 0 )
+ {
+ efsw::System::sleep( 1000 );
+ fileWatcher.removeWatch( watchID );
+ }
+ }
+ else
+ {
+ efsw::WatchID err;
+
+ if ( ( err = fileWatcher.addWatch( path, ul, true ) ) > 0 )
+ {
+ fileWatcher.watch();
+
+ std::cout << "Watching directory: " << path.c_str() << std::endl;
+
+ if ( useGeneric )
+ {
+ std::cout << "Using generic backend watcher" << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "Error trying to watch directory: " << path.c_str() << std::endl;
+ std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl;
+ }
+ }
+
+ while( !STOP )
+ {
+ efsw::System::sleep( 100 );
+ }
+
+ return 0;
+}
diff --git a/dep/g3dlite/CMakeLists.txt b/dep/g3dlite/CMakeLists.txt
index f1166c72e6d..4e579951d63 100644
--- a/dep/g3dlite/CMakeLists.txt
+++ b/dep/g3dlite/CMakeLists.txt
@@ -8,7 +8,6 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
set(g3dlib_STAT_SRCS
source/AABox.cpp
source/Any.cpp
@@ -55,20 +54,18 @@ set(g3dlib_STAT_SRCS
source/Vector4.cpp
)
-if(WIN32)
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${CMAKE_SOURCE_DIR}/dep/zlib
- )
-else()
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- )
-endif()
-
add_library(g3dlib STATIC ${g3dlib_STAT_SRCS})
+target_include_directories(g3dlib
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
target_link_libraries(g3dlib
- ${ZLIB_LIBRARIES}
- ${CMAKE_THREAD_LIBS_INIT}
-)
+ PUBLIC
+ zlib
+ threads)
+
+set_target_properties(g3dlib
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/gsoap/CMakeLists.txt b/dep/gsoap/CMakeLists.txt
index b5fed7809af..bdcadf6e4dc 100644
--- a/dep/gsoap/CMakeLists.txt
+++ b/dep/gsoap/CMakeLists.txt
@@ -10,17 +10,22 @@
file(GLOB sources *.cpp *.h)
-set(gsoap_STAT_SRCS
- ${sources}
-)
+add_library(gsoap STATIC ${sources})
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
-)
+set_target_properties(gsoap PROPERTIES LINKER_LANGUAGE CXX)
-# Little fix for MSVC / Windows platforms
-add_definitions(-D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=0)
+target_include_directories(gsoap
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
-add_library(gsoap STATIC ${gsoap_STAT_SRCS})
+set_target_properties(gsoap
+ PROPERTIES
+ FOLDER
+ "dep")
-set_target_properties(gsoap PROPERTIES LINKER_LANGUAGE CXX)
+if (MSVC)
+ # Little fix for MSVC / Windows platforms
+ target_compile_definitions(gsoap
+ PRIVATE
+ -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=0)
+endif()
diff --git a/dep/jemalloc/CMakeLists.txt b/dep/jemalloc/CMakeLists.txt
index cf0ac435f0a..6774e5a75d2 100644
--- a/dep/jemalloc/CMakeLists.txt
+++ b/dep/jemalloc/CMakeLists.txt
@@ -8,54 +8,79 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# We need to generate the jemalloc_def.h header based on platform-specific settings
-if (PLATFORM EQUAL 32)
- set(JEM_SIZEDEF 2)
- set(JEM_TLSMODEL)
+if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT NOJEM)
+ # We need to generate the jemalloc_def.h header based on platform-specific settings
+ if (PLATFORM EQUAL 32)
+ set(JEM_SIZEDEF 2)
+ set(JEM_TLSMODEL)
+ else()
+ set(JEM_SIZEDEF 3)
+ set(JEM_TLSMODEL "__attribute__\(\(tls_model\(\"initial-exec\"\)\)\)")
+ endif()
+
+ # Create the header, so we can use it
+ configure_file(
+ "${CMAKE_SOURCE_DIR}/dep/jemalloc/jemalloc_defs.h.in.cmake"
+ "${BUILDDIR}/jemalloc_defs.h"
+ @ONLY
+ )
+
+ # Done, let's continue
+ set(jemalloc_STAT_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/arena.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/atomic.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/base.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/bitmap.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_dss.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_mmap.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ckh.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ctl.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/extent.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hash.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/huge.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/jemalloc.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/mb.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/mutex.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/prof.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/quarantine.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/rtree.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/stats.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/tcache.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/tsd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
+ )
+
+ add_library(jemalloc STATIC ${jemalloc_STAT_SRC})
+
+ target_include_directories(jemalloc
+ PRIVATE
+ ${BUILDDIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+ target_compile_definitions(jemalloc
+ PUBLIC
+ -DNO_BUFFERPOOL
+ PRIVATE
+ -D_GNU_SOURCE
+ -D_REENTRAN)
+
+ target_link_libraries(jemalloc
+ PUBLIC
+ threads
+ valgrind)
+
+ set_target_properties(jemalloc
+ PROPERTIES
+ FOLDER
+ "dep")
+
else()
- set(JEM_SIZEDEF 3)
- set(JEM_TLSMODEL "__attribute__\(\(tls_model\(\"initial-exec\"\)\)\)")
-endif()
+ # Provide a dummy target for jemalloc which is used when jemalloc
+ # is disabled or not supported.
+ add_library(jemalloc INTERFACE)
+ target_link_libraries(jemalloc
+ INTERFACE
+ valgrind)
-# Create the header, so we can use it
-configure_file(
- "${CMAKE_SOURCE_DIR}/dep/jemalloc/jemalloc_defs.h.in.cmake"
- "${BUILDDIR}/jemalloc_defs.h"
- @ONLY
-)
-
-# Done, let's continue
-set(jemalloc_STAT_SRC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/arena.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/atomic.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/base.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/bitmap.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_dss.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_mmap.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/ckh.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/ctl.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/extent.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/hash.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/huge.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/jemalloc.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/mb.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/mutex.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/prof.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/quarantine.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/rtree.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/stats.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/tcache.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/tsd.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
-)
-
-include_directories(
- ${BUILDDIR}/
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${VALGRIND_INCLUDE_DIR}
-)
-
-add_definitions(-D_GNU_SOURCE -D_REENTRANT)
-
-add_library(jemalloc STATIC ${jemalloc_STAT_SRC})
+endif()
diff --git a/dep/zmqpp/CMakeLists.txt b/dep/mysql/CMakeLists.txt
index 24b1d08c265..472535b0356 100644
--- a/dep/zmqpp/CMakeLists.txt
+++ b/dep/mysql/CMakeLists.txt
@@ -8,24 +8,15 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-file(GLOB_RECURSE sources_zmqpp zmqpp/*.cpp zmqpp/*.hpp zmqpp/*.h)
-
-set(zmqpp_STAT_SRCS
- ${sources_zmqpp}
-)
-
-include_directories(${ZMQ_INCLUDE_DIR})
-
-add_library(zmqpp STATIC
- ${zmqpp_STAT_SRCS}
-)
-
-if (WIN32)
- add_definitions(-DBUILD_VERSION=\\"3.2.0\\")
-else()
- add_definitions(-DBUILD_VERSION='"3.2.0"')
+if (NOT MYSQL_FOUND)
+ message(FATAL_ERROR "MySQL wasn't found on your system but it's required to build the servers!")
endif()
-add_definitions(-DBUILD_VERSION_MAJOR=3)
-add_definitions(-DBUILD_VERSION_MINOR=2)
-add_definitions(-DBUILD_VERSION_REVISION=0)
+add_library(mysql STATIC IMPORTED GLOBAL)
+
+set_target_properties(mysql
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${MYSQL_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${MYSQL_INCLUDE_DIR}")
diff --git a/dep/openssl/CMakeLists.txt b/dep/openssl/CMakeLists.txt
new file mode 100644
index 00000000000..98561b2a0ed
--- /dev/null
+++ b/dep/openssl/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+
+# basic packagesearching and setup
+# (further support will be needed, this is a preliminary release!)
+set(OPENSSL_EXPECTED_VERSION 1.0.0)
+
+find_package(OpenSSL REQUIRED)
+
+add_library(openssl INTERFACE)
+
+target_link_libraries(openssl
+ INTERFACE
+ ${OPENSSL_LIBRARIES})
+
+target_include_directories(openssl
+ INTERFACE
+ ${OPENSSL_INCLUDE_DIR})
diff --git a/dep/process/CMakeLists.txt b/dep/process/CMakeLists.txt
new file mode 100644
index 00000000000..5a51917a00c
--- /dev/null
+++ b/dep/process/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+add_library(process INTERFACE)
+
+target_include_directories(process
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+target_link_libraries(process
+ INTERFACE
+ boost)
diff --git a/dep/rapidjson/CMakeLists.txt b/dep/rapidjson/CMakeLists.txt
new file mode 100644
index 00000000000..de1466a41a6
--- /dev/null
+++ b/dep/rapidjson/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+add_library(rapidjson INTERFACE)
+
+target_include_directories(rapidjson
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+target_compile_definitions(rapidjson
+ INTERFACE
+ -DRAPIDJSON_HAS_STDSTRING
+ -DRAPIDJSON_SSE2)
diff --git a/dep/rapidjson/rapidjson/allocators.h b/dep/rapidjson/rapidjson/allocators.h
new file mode 100644
index 00000000000..d74a67155b4
--- /dev/null
+++ b/dep/rapidjson/rapidjson/allocators.h
@@ -0,0 +1,261 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ALLOCATORS_H_
+#define RAPIDJSON_ALLOCATORS_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+ \brief Concept for allocating, resizing and freeing memory block.
+
+ Note that Malloc() and Realloc() are non-static but Free() is static.
+
+ So if an allocator need to support Free(), it needs to put its pointer in
+ the header of memory block.
+
+\code
+concept Allocator {
+ static const bool kNeedFree; //!< Whether this allocator needs to call Free().
+
+ // Allocate a memory block.
+ // \param size of the memory block in bytes.
+ // \returns pointer to the memory block.
+ void* Malloc(size_t size);
+
+ // Resize a memory block.
+ // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+ // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+ // \param newSize the new size in bytes.
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // Free a memory block.
+ // \param pointer to the memory block. Null pointer is permitted.
+ static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+ \note implements Allocator concept
+*/
+class CrtAllocator {
+public:
+ static const bool kNeedFree = true;
+ void* Malloc(size_t size) {
+ if (size) // behavior of malloc(0) is implementation defined.
+ return std::malloc(size);
+ else
+ return NULL; // standardize to returning NULL.
+ }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ (void)originalSize;
+ if (newSize == 0) {
+ std::free(originalPtr);
+ return NULL;
+ }
+ return std::realloc(originalPtr, newSize);
+ }
+ static void Free(void *ptr) { std::free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks.
+
+ It does not free memory blocks. And Realloc() only allocate new memory.
+
+ The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+ User may also supply a buffer as the first chunk.
+
+ If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+ The user-buffer is not deallocated by this allocator.
+
+ \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+ \note implements Allocator concept
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+ static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+ //! Constructor with chunkSize.
+ /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ }
+
+ //! Constructor with user-supplied buffer.
+ /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+ The user buffer will not be deallocated when this allocator is destructed.
+
+ \param buffer User supplied buffer.
+ \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+ \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ RAPIDJSON_ASSERT(buffer != 0);
+ RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+ chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
+ chunkHead_->capacity = size - sizeof(ChunkHeader);
+ chunkHead_->size = 0;
+ chunkHead_->next = 0;
+ }
+
+ //! Destructor.
+ /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+ */
+ ~MemoryPoolAllocator() {
+ Clear();
+ RAPIDJSON_DELETE(ownBaseAllocator_);
+ }
+
+ //! Deallocates all memory chunks, excluding the user-supplied buffer.
+ void Clear() {
+ while (chunkHead_ && chunkHead_ != userBuffer_) {
+ ChunkHeader* next = chunkHead_->next;
+ baseAllocator_->Free(chunkHead_);
+ chunkHead_ = next;
+ }
+ if (chunkHead_ && chunkHead_ == userBuffer_)
+ chunkHead_->size = 0; // Clear user buffer
+ }
+
+ //! Computes the total capacity of allocated memory chunks.
+ /*! \return total capacity in bytes.
+ */
+ size_t Capacity() const {
+ size_t capacity = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ capacity += c->capacity;
+ return capacity;
+ }
+
+ //! Computes the memory blocks allocated.
+ /*! \return total used bytes.
+ */
+ size_t Size() const {
+ size_t size = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ size += c->size;
+ return size;
+ }
+
+ //! Allocates a memory block. (concept Allocator)
+ void* Malloc(size_t size) {
+ if (!size)
+ return NULL;
+
+ size = RAPIDJSON_ALIGN(size);
+ if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+ AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
+
+ void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
+ chunkHead_->size += size;
+ return buffer;
+ }
+
+ //! Resizes a memory block (concept Allocator)
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ if (originalPtr == 0)
+ return Malloc(newSize);
+
+ if (newSize == 0)
+ return NULL;
+
+ // Do not shrink if new size is smaller than original
+ if (originalSize >= newSize)
+ return originalPtr;
+
+ // Simply expand it if it is the last allocation and there is sufficient space
+ if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
+ size_t increment = static_cast<size_t>(newSize - originalSize);
+ increment = RAPIDJSON_ALIGN(increment);
+ if (chunkHead_->size + increment <= chunkHead_->capacity) {
+ chunkHead_->size += increment;
+ return originalPtr;
+ }
+ }
+
+ // Realloc process: allocate and copy memory, do not free original buffer.
+ void* newBuffer = Malloc(newSize);
+ RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
+ if (originalSize)
+ std::memcpy(newBuffer, originalPtr, originalSize);
+ return newBuffer;
+ }
+
+ //! Frees a memory block (concept Allocator)
+ static void Free(void *ptr) { (void)ptr; } // Do nothing
+
+private:
+ //! Copy constructor is not permitted.
+ MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
+ //! Copy assignment operator is not permitted.
+ MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+
+ //! Creates a new chunk.
+ /*! \param capacity Capacity of the chunk in bytes.
+ */
+ void AddChunk(size_t capacity) {
+ if (!baseAllocator_)
+ ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
+ ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
+ chunk->capacity = capacity;
+ chunk->size = 0;
+ chunk->next = chunkHead_;
+ chunkHead_ = chunk;
+ }
+
+ static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
+ void *userBuffer_; //!< User supplied buffer.
+ BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
+ BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/dep/rapidjson/rapidjson/document.h b/dep/rapidjson/rapidjson/document.h
new file mode 100644
index 00000000000..c6acbd907ab
--- /dev/null
+++ b/dep/rapidjson/rapidjson/document.h
@@ -0,0 +1,2014 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+#include "reader.h"
+#include "internal/meta.h"
+#include "internal/strfunc.h"
+#include <new> // placement new
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_HAS_STDSTRING
+
+#ifndef RAPIDJSON_HAS_STDSTRING
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
+#else
+#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
+#endif
+/*! \def RAPIDJSON_HAS_STDSTRING
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable RapidJSON support for \c std::string
+
+ By defining this preprocessor symbol to \c 1, several convenience functions for using
+ \ref rapidjson::GenericValue with \c std::string are enabled, especially
+ for construction and comparison.
+
+ \hideinitializer
+*/
+#endif // !defined(RAPIDJSON_HAS_STDSTRING)
+
+#if RAPIDJSON_HAS_STDSTRING
+#include <string>
+#endif // RAPIDJSON_HAS_STDSTRING
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+#include <iterator> // std::iterator, std::random_access_iterator_tag
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// Forward declaration.
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+//! Name-value pair in a JSON object value.
+/*!
+ This class was internal to GenericValue. It used to be a inner struct.
+ But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
+ https://code.google.com/p/rapidjson/issues/detail?id=64
+*/
+template <typename Encoding, typename Allocator>
+struct GenericMember {
+ GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
+ GenericValue<Encoding, Allocator> value; //!< value of member.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericMemberIterator
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+
+//! (Constant) member iterator for a JSON object value
+/*!
+ \tparam Const Is this a constant iterator?
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+
+ This class implements a Random Access Iterator for GenericMember elements
+ of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
+
+ \note This iterator implementation is mainly intended to avoid implicit
+ conversions from iterator values to \c NULL,
+ e.g. from GenericValue::FindMember.
+
+ \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+ pointer-based implementation, if your platform doesn't provide
+ the C++ <iterator> header.
+
+ \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
+ */
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator
+ : public std::iterator<std::random_access_iterator_tag
+ , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
+
+ friend class GenericValue<Encoding,Allocator>;
+ template <bool, typename, typename> friend class GenericMemberIterator;
+
+ typedef GenericMember<Encoding,Allocator> PlainType;
+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+ typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
+
+public:
+ //! Iterator type itself
+ typedef GenericMemberIterator Iterator;
+ //! Constant iterator type
+ typedef GenericMemberIterator<true,Encoding,Allocator> ConstIterator;
+ //! Non-constant iterator type
+ typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
+
+ //! Pointer to (const) GenericMember
+ typedef typename BaseType::pointer Pointer;
+ //! Reference to (const) GenericMember
+ typedef typename BaseType::reference Reference;
+ //! Signed integer type (e.g. \c ptrdiff_t)
+ typedef typename BaseType::difference_type DifferenceType;
+
+ //! Default constructor (singular value)
+ /*! Creates an iterator pointing to no element.
+ \note All operations, except for comparisons, are undefined on such values.
+ */
+ GenericMemberIterator() : ptr_() {}
+
+ //! Iterator conversions to more const
+ /*!
+ \param it (Non-const) iterator to copy from
+
+ Allows the creation of an iterator from another GenericMemberIterator
+ that is "less const". Especially, creating a non-constant iterator
+ from a constant iterator are disabled:
+ \li const -> non-const (not ok)
+ \li const -> const (ok)
+ \li non-const -> const (ok)
+ \li non-const -> non-const (ok)
+
+ \note If the \c Const template parameter is already \c false, this
+ constructor effectively defines a regular copy-constructor.
+ Otherwise, the copy constructor is implicitly defined.
+ */
+ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
+
+ //! @name stepping
+ //@{
+ Iterator& operator++(){ ++ptr_; return *this; }
+ Iterator& operator--(){ --ptr_; return *this; }
+ Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; }
+ Iterator operator--(int){ Iterator old(*this); --ptr_; return old; }
+ //@}
+
+ //! @name increment/decrement
+ //@{
+ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
+ Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
+
+ Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
+ Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
+ //@}
+
+ //! @name relations
+ //@{
+ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
+ bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
+ bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
+ bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
+ bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
+ bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
+ //@}
+
+ //! @name dereference
+ //@{
+ Reference operator*() const { return *ptr_; }
+ Pointer operator->() const { return ptr_; }
+ Reference operator[](DifferenceType n) const { return ptr_[n]; }
+ //@}
+
+ //! Distance
+ DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
+
+private:
+ //! Internal constructor from plain pointer
+ explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
+
+ Pointer ptr_; //!< raw pointer
+};
+
+#else // RAPIDJSON_NOMEMBERITERATORCLASS
+
+// class-based member iterator implementation disabled, use plain pointers
+
+template <bool Const, typename Encoding, typename Allocator>
+struct GenericMemberIterator;
+
+//! non-const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<false,Encoding,Allocator> {
+ //! use plain pointer as iterator type
+ typedef GenericMember<Encoding,Allocator>* Iterator;
+};
+//! const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<true,Encoding,Allocator> {
+ //! use plain const pointer as iterator type
+ typedef const GenericMember<Encoding,Allocator>* Iterator;
+};
+
+#endif // RAPIDJSON_NOMEMBERITERATORCLASS
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStringRef
+
+//! Reference to a constant string (not taking a copy)
+/*!
+ \tparam CharType character type of the string
+
+ This helper class is used to automatically infer constant string
+ references for string literals, especially from \c const \b (!)
+ character arrays.
+
+ The main use is for creating JSON string values without copying the
+ source string via an \ref Allocator. This requires that the referenced
+ string pointers have a sufficient lifetime, which exceeds the lifetime
+ of the associated GenericValue.
+
+ \b Example
+ \code
+ Value v("foo"); // ok, no need to copy & calculate length
+ const char foo[] = "foo";
+ v.SetString(foo); // ok
+
+ const char* bar = foo;
+ // Value x(bar); // not ok, can't rely on bar's lifetime
+ Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
+ Value y(StringRef(bar, 3)); // ok, explicitly pass length
+ \endcode
+
+ \see StringRef, GenericValue::SetString
+*/
+template<typename CharType>
+struct GenericStringRef {
+ typedef CharType Ch; //!< character type of the string
+
+ //! Create string reference from \c const character array
+ /*!
+ This constructor implicitly creates a constant string reference from
+ a \c const character array. It has better performance than
+ \ref StringRef(const CharType*) by inferring the string \ref length
+ from the array length, and also supports strings containing null
+ characters.
+
+ \tparam N length of the string, automatically inferred
+
+ \param str Constant character array, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note Constant complexity.
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+ template<SizeType N>
+ GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
+ : s(str), length(N-1) {}
+
+ //! Explicitly create string reference from \c const character pointer
+ /*!
+ This constructor can be used to \b explicitly create a reference to
+ a constant string pointer.
+
+ \see StringRef(const CharType*)
+
+ \param str Constant character pointer, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+ explicit GenericStringRef(const CharType* str)
+ : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
+
+ //! Create constant string reference from pointer and length
+ /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param len length of the string, excluding the trailing NULL terminator
+
+ \post \ref s == str && \ref length == len
+ \note Constant complexity.
+ */
+ GenericStringRef(const CharType* str, SizeType len)
+ : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
+
+ //! implicit conversion to plain CharType pointer
+ operator const Ch *() const { return s; }
+
+ const Ch* const s; //!< plain CharType pointer
+ const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
+
+private:
+ //! Disallow copy-assignment
+ GenericStringRef operator=(const GenericStringRef&);
+ //! Disallow construction from non-const array
+ template<SizeType N>
+ GenericStringRef(CharType (&str)[N]) /* = delete */;
+};
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+ \tparam CharType Character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+
+ \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str) {
+ return GenericStringRef<CharType>(str, internal::StrLen(str));
+}
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ This version has better performance with supplied length, and also
+ supports string containing null characters.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param length The length of source string.
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
+ return GenericStringRef<CharType>(str, SizeType(length));
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+//! Mark a string object as constant string
+/*! Mark a string object (e.g. \c std::string) as a "string literal".
+ This function can be used to avoid copying a string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
+ return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue type traits
+namespace internal {
+
+template <typename T, typename Encoding = void, typename Allocator = void>
+struct IsGenericValueImpl : FalseType {};
+
+// select candidates according to nested encoding and allocator types
+template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
+ : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
+
+// helper to match arbitrary GenericValue instantiations, including derived classes
+template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+ A JSON value can be one of 7 types. This class is a variant type supporting
+ these types.
+
+ Use the Value if UTF8 and default allocator
+
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+public:
+ //! Name-value pair in an object.
+ typedef GenericMember<Encoding, Allocator> Member;
+ typedef Encoding EncodingType; //!< Encoding type from template parameter.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string
+ typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
+ typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
+ typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
+ typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor creates a null value.
+ GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {
+ rhs.flags_ = kNullFlag; // give up contents
+ }
+#endif
+
+private:
+ //! Copy constructor is not permitted.
+ GenericValue(const GenericValue& rhs);
+
+public:
+
+ //! Constructor with JSON value type.
+ /*! This creates a Value of specified type with default content.
+ \param type Type of the value.
+ \note Default content for number is zero.
+ */
+ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
+ static const unsigned defaultFlags[7] = {
+ kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
+ kNumberAnyFlag
+ };
+ RAPIDJSON_ASSERT(type <= kNumberType);
+ flags_ = defaultFlags[type];
+
+ // Use ShortString to store empty string.
+ if (type == kStringType)
+ data_.ss.SetLength(0);
+ }
+
+ //! Explicit copy constructor (with allocator)
+ /*! Creates a copy of a Value by using the given Allocator
+ \tparam SourceAllocator allocator of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+ \see CopyFrom()
+ */
+ template< typename SourceAllocator >
+ GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
+
+ //! Constructor for boolean value.
+ /*! \param b Boolean value
+ \note This constructor is limited to \em real boolean values and rejects
+ implicitly converted types like arbitrary pointers. Use an explicit cast
+ to \c bool, if you want to construct a boolean JSON value in such cases.
+ */
+#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
+ template <typename T>
+ explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT
+#else
+ explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
+#endif
+ : data_(), flags_(b ? kTrueFlag : kFalseFlag) {
+ // safe-guard against failing SFINAE
+ RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
+ }
+
+ //! Constructor for int value.
+ explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
+ data_.n.i64 = i;
+ if (i >= 0)
+ flags_ |= kUintFlag | kUint64Flag;
+ }
+
+ //! Constructor for unsigned value.
+ explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {
+ data_.n.u64 = u;
+ if (!(u & 0x80000000))
+ flags_ |= kIntFlag | kInt64Flag;
+ }
+
+ //! Constructor for int64_t value.
+ explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) {
+ data_.n.i64 = i64;
+ if (i64 >= 0) {
+ flags_ |= kNumberUint64Flag;
+ if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ flags_ |= kUintFlag;
+ if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ flags_ |= kIntFlag;
+ }
+ else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for uint64_t value.
+ explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
+ data_.n.u64 = u64;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
+ flags_ |= kInt64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ flags_ |= kUintFlag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for double value.
+ explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor for copy-string from a string object (i.e. do make a copy of string)
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
+#endif
+
+ //! Destructor.
+ /*! Need to destruct elements of array, members of object, or copy-string.
+ */
+ ~GenericValue() {
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ switch(flags_) {
+ case kArrayFlag:
+ for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ v->~GenericValue();
+ Allocator::Free(data_.a.elements);
+ break;
+
+ case kObjectFlag:
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ Allocator::Free(data_.o.members);
+ break;
+
+ case kCopyStringFlag:
+ Allocator::Free(const_cast<Ch*>(data_.s.str));
+ break;
+
+ default:
+ break; // Do nothing for other types.
+ }
+ }
+ }
+
+ //@}
+
+ //!@name Assignment operators
+ //@{
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. It will become a null value after assignment.
+ */
+ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_ASSERT(this != &rhs);
+ this->~GenericValue();
+ RawAssign(rhs);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
+ return *this = rhs.Move();
+ }
+#endif
+
+ //! Assignment of constant string reference (no copy)
+ /*! \param str Constant string reference to be assigned
+ \note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
+ \see GenericStringRef, operator=(T)
+ */
+ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
+ GenericValue s(str);
+ return *this = s;
+ }
+
+ //! Assignment with primitive types.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value The value to be assigned.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref SetString(const Ch*, Allocator&) (for copying) or
+ \ref StringRef() (to explicitly mark the pointer as constant) instead.
+ All other pointer types would implicitly convert to \c bool,
+ use \ref SetBool() instead.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
+ operator=(T value) {
+ GenericValue v(value);
+ return *this = v;
+ }
+
+ //! Deep-copy assignment from Value
+ /*! Assigns a \b copy of the Value to the current Value object
+ \tparam SourceAllocator Allocator type of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator to use for copying
+ */
+ template <typename SourceAllocator>
+ GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
+ RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
+ this->~GenericValue();
+ new (this) GenericValue(rhs, allocator);
+ return *this;
+ }
+
+ //! Exchange the contents of this value with those of other.
+ /*!
+ \param other Another value.
+ \note Constant complexity.
+ */
+ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
+ GenericValue temp;
+ temp.RawAssign(*this);
+ RawAssign(other);
+ other.RawAssign(temp);
+ return *this;
+ }
+
+ //! Prepare Value for move semantics
+ /*! \return *this */
+ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
+ //@}
+
+ //!@name Equal-to and not-equal-to operators
+ //@{
+ //! Equal-to operator
+ /*!
+ \note If an object contains duplicated named member, comparing equality with any object is always \c false.
+ \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
+ */
+ template <typename SourceAllocator>
+ bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ typedef GenericValue<Encoding, SourceAllocator> RhsType;
+ if (GetType() != rhs.GetType())
+ return false;
+
+ switch (GetType()) {
+ case kObjectType: // Warning: O(n^2) inner-loop
+ if (data_.o.size != rhs.data_.o.size)
+ return false;
+ for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
+ typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
+ if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
+ return false;
+ }
+ return true;
+
+ case kArrayType:
+ if (data_.a.size != rhs.data_.a.size)
+ return false;
+ for (SizeType i = 0; i < data_.a.size; i++)
+ if ((*this)[i] != rhs[i])
+ return false;
+ return true;
+
+ case kStringType:
+ return StringEqual(rhs);
+
+ case kNumberType:
+ if (IsDouble() || rhs.IsDouble()) {
+ double a = GetDouble(); // May convert from integer to double.
+ double b = rhs.GetDouble(); // Ditto
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+ else
+ return data_.n.u64 == rhs.data_.n.u64;
+
+ default: // kTrueType, kFalseType, kNullType
+ return true;
+ }
+ }
+
+ //! Equal-to operator with const C-string pointer
+ bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Equal-to operator with string object
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
+#endif
+
+ //! Equal-to operator with primitive types
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
+ */
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
+
+ //! Not-equal-to operator
+ /*! \return !(*this == rhs)
+ */
+ template <typename SourceAllocator>
+ bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with const C-string pointer
+ bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with arbitrary types
+ /*! \return !(*this == rhs)
+ */
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
+
+ //! Equal-to operator with arbitrary types (symmetric version)
+ /*! \return (rhs == lhs)
+ */
+ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
+
+ //! Not-Equal-to operator with arbitrary types (symmetric version)
+ /*! \return !(rhs == lhs)
+ */
+ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
+ bool IsNull() const { return flags_ == kNullFlag; }
+ bool IsFalse() const { return flags_ == kFalseFlag; }
+ bool IsTrue() const { return flags_ == kTrueFlag; }
+ bool IsBool() const { return (flags_ & kBoolFlag) != 0; }
+ bool IsObject() const { return flags_ == kObjectFlag; }
+ bool IsArray() const { return flags_ == kArrayFlag; }
+ bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
+ bool IsInt() const { return (flags_ & kIntFlag) != 0; }
+ bool IsUint() const { return (flags_ & kUintFlag) != 0; }
+ bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
+ bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
+ bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
+ bool IsString() const { return (flags_ & kStringFlag) != 0; }
+
+ //@}
+
+ //!@name Null
+ //@{
+
+ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+ //@}
+
+ //!@name Bool
+ //@{
+
+ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
+ //!< Set boolean value
+ /*! \post IsBool() == true */
+ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+ //@}
+
+ //!@name Object
+ //@{
+
+ //! Set this value as an empty object.
+ /*! \post IsObject() == true */
+ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+ //! Get the number of members in the object.
+ SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+
+ //! Check whether the object is empty.
+ bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
+ \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
+ Since 0.2, if the name is not correct, it will assert.
+ If user is unsure whether a member exists, user should use HasMember() first.
+ A better approach is to use FindMember().
+ \note Linear time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
+ GenericValue n(StringRef(name));
+ return (*this)[n];
+ }
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam SourceAllocator Allocator of the \c name value
+
+ \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
+ And it can also handle strings with embedded null characters.
+
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator member = FindMember(name);
+ if (member != MemberEnd())
+ return member->value;
+ else {
+ RAPIDJSON_ASSERT(false); // see above note
+ static GenericValue NullValue;
+ return NullValue;
+ }
+ }
+ template <typename SourceAllocator>
+ const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Get a value from an object associated with name (string object).
+ GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
+ const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
+#endif
+
+ //! Const member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
+ //! Const \em past-the-end member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); }
+ //! Member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); }
+ //! \em Past-the-end member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); }
+
+ //! Check whether a member exists in the object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Check whether a member exists in the object with string object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
+#endif
+
+ //! Check whether a member exists in the object with GenericValue name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
+
+ //! Find member by name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ MemberIterator FindMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return FindMember(n);
+ }
+
+ ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+ //! Find member by name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+ MemberIterator member = MemberBegin();
+ for ( ; member != MemberEnd(); ++member)
+ if (name.StringEqual(member->name))
+ break;
+ return member;
+ }
+ template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Find member by string object name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+ */
+ MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(StringRef(name)); }
+ ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(StringRef(name)); }
+#endif
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c name and \c value will be transferred to this object on success.
+ \pre IsObject() && name.IsString()
+ \post name.IsNull() && value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+
+ Object& o = data_.o;
+ if (o.size >= o.capacity) {
+ if (o.capacity == 0) {
+ o.capacity = kDefaultObjectCapacity;
+ o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
+ }
+ else {
+ SizeType oldCapacity = o.capacity;
+ o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
+ o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
+ }
+ }
+ o.members[o.size].name.RawAssign(name);
+ o.members[o.size].value.RawAssign(value);
+ o.size++;
+ return *this;
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Add a string object as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
+ GenericValue v(value, allocator);
+ return AddMember(name, v, allocator);
+ }
+#endif
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A string value as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ AddMember(GenericValue& name, T value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this object on success.
+ \pre IsObject()
+ \post value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A constant string reference as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ AddMember(StringRefType name, T value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Remove all members in the object.
+ /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void RemoveAllMembers() {
+ RAPIDJSON_ASSERT(IsObject());
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ data_.o.size = 0;
+ }
+
+ //! Remove a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Linear time complexity.
+ */
+ bool RemoveMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return RemoveMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
+#endif
+
+ template <typename SourceAllocator>
+ bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ RemoveMember(m);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ //! Remove a member in object by iterator.
+ /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
+ \return the new iterator after removal.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Constant time complexity.
+ */
+ MemberIterator RemoveMember(MemberIterator m) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(data_.o.members != 0);
+ RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
+
+ MemberIterator last(data_.o.members + (data_.o.size - 1));
+ if (data_.o.size > 1 && m != last) {
+ // Move the last one to this place
+ *m = *last;
+ }
+ else {
+ // Only one left, just destroy
+ m->~Member();
+ }
+ --data_.o.size;
+ return m;
+ }
+
+ //! Remove a member from an object by iterator.
+ /*! \param pos iterator to the member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
+ \return Iterator following the removed element.
+ If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
+ \note This function preserves the relative order of the remaining object
+ members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator pos) {
+ return EraseMember(pos, pos +1);
+ }
+
+ //! Remove members in the range [first, last) from an object.
+ /*! \param first iterator to the first member to remove
+ \param last iterator following the last member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
+ \return Iterator following the last removed element.
+ \note This function preserves the relative order of the remaining object
+ members.
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(data_.o.members != 0);
+ RAPIDJSON_ASSERT(first >= MemberBegin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= MemberEnd());
+
+ MemberIterator pos = MemberBegin() + (first - MemberBegin());
+ for (MemberIterator itr = pos; itr != last; ++itr)
+ itr->~Member();
+ std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member));
+ data_.o.size -= (last - first);
+ return pos;
+ }
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Set this value as an empty array.
+ /*! \post IsArray == true */
+ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+ //! Get the number of elements in array.
+ SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+ //! Get the capacity of array.
+ SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+ //! Check whether the array is empty.
+ bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+ //! Remove all elements in the array.
+ /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void Clear() {
+ RAPIDJSON_ASSERT(IsArray());
+ for (SizeType i = 0; i < data_.a.size; ++i)
+ data_.a.elements[i].~GenericValue();
+ data_.a.size = 0;
+ }
+
+ //! Get an element from array by index.
+ /*! \pre IsArray() == true
+ \param index Zero-based index of element.
+ \see operator[](T*)
+ */
+ GenericValue& operator[](SizeType index) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(index < data_.a.size);
+ return data_.a.elements[index];
+ }
+ const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+ //! Element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
+ //! \em Past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
+ //! Constant element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+ //! Constant \em past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+ //! Request the array to have enough capacity to store elements.
+ /*! \param newCapacity The capacity that the array at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note Linear time complexity.
+ */
+ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (newCapacity > data_.a.capacity) {
+ data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
+ data_.a.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Append a GenericValue at the end of the array.
+ /*! \param value Value to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \post value.IsNull() == true
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this array on success.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ */
+ GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (data_.a.size >= data_.a.capacity)
+ Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
+ data_.a.elements[data_.a.size++].RawAssign(value);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
+ return PushBack(value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+ //! Append a constant string reference at the end of the array.
+ /*! \param value Constant string reference to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ \see GenericStringRef
+ */
+ GenericValue& PushBack(StringRefType value, Allocator& allocator) {
+ return (*this).template PushBack<StringRefType>(value, allocator);
+ }
+
+ //! Append a primitive value at the end of the array.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value Value of primitive type T to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref PushBack(GenericValue&, Allocator&) or \ref
+ PushBack(StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ PushBack(T value, Allocator& allocator) {
+ GenericValue v(value);
+ return PushBack(v, allocator);
+ }
+
+ //! Remove the last element in the array.
+ /*!
+ \note Constant time complexity.
+ */
+ GenericValue& PopBack() {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(!Empty());
+ data_.a.elements[--data_.a.size].~GenericValue();
+ return *this;
+ }
+
+ //! Remove an element of array by iterator.
+ /*!
+ \param pos iterator to the element to remove
+ \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
+ \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator pos) {
+ return Erase(pos, pos + 1);
+ }
+
+ //! Remove elements in the range [first, last) of the array.
+ /*!
+ \param first iterator to the first element to remove
+ \param last iterator following the last element to remove
+ \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
+ \return Iterator following the last removed element.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(data_.a.size > 0);
+ RAPIDJSON_ASSERT(data_.a.elements != 0);
+ RAPIDJSON_ASSERT(first >= Begin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= End());
+ ValueIterator pos = Begin() + (first - Begin());
+ for (ValueIterator itr = pos; itr != last; ++itr)
+ itr->~GenericValue();
+ std::memmove(pos, last, (End() - last) * sizeof(GenericValue));
+ data_.a.size -= (last - first);
+ return pos;
+ }
+
+ //@}
+
+ //!@name Number
+ //@{
+
+ int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; }
+ unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; }
+ int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
+ uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
+
+ double GetDouble() const {
+ RAPIDJSON_ASSERT(IsNumber());
+ if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
+ if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
+ if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
+ if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision)
+ }
+
+ GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
+ GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
+ GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
+ GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
+ GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); }
+
+ //! Get the length of string.
+ /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+ */
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+
+ //! Set this value as a string without copying source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string pointer.
+ \param length The length of source string, excluding the trailing null terminator.
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == length
+ \see SetString(StringRefType)
+ */
+ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
+
+ //! Set this value as a string without copying source string.
+ /*! \param s source string reference
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == s.length
+ */
+ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string.
+ \param length The length of source string, excluding the trailing null terminator.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
+#endif
+
+ //@}
+
+ //! Generate events of this value to a Handler.
+ /*! This function adopts the GoF visitor pattern.
+ Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+ It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+ \tparam Handler type of handler.
+ \param handler An object implementing concept Handler.
+ */
+ template <typename Handler>
+ bool Accept(Handler& handler) const {
+ switch(GetType()) {
+ case kNullType: return handler.Null();
+ case kFalseType: return handler.Bool(false);
+ case kTrueType: return handler.Bool(true);
+
+ case kObjectType:
+ if (!handler.StartObject())
+ return false;
+ for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
+ RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
+ if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0))
+ return false;
+ if (!m->value.Accept(handler))
+ return false;
+ }
+ return handler.EndObject(data_.o.size);
+
+ case kArrayType:
+ if (!handler.StartArray())
+ return false;
+ for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ if (!v->Accept(handler))
+ return false;
+ return handler.EndArray(data_.a.size);
+
+ case kStringType:
+ return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
+
+ default:
+ RAPIDJSON_ASSERT(GetType() == kNumberType);
+ if (IsInt()) return handler.Int(data_.n.i.i);
+ else if (IsUint()) return handler.Uint(data_.n.u.u);
+ else if (IsInt64()) return handler.Int64(data_.n.i64);
+ else if (IsUint64()) return handler.Uint64(data_.n.u64);
+ else return handler.Double(data_.n.d);
+ }
+ }
+
+private:
+ template <typename, typename> friend class GenericValue;
+ template <typename, typename, typename> friend class GenericDocument;
+
+ enum {
+ kBoolFlag = 0x100,
+ kNumberFlag = 0x200,
+ kIntFlag = 0x400,
+ kUintFlag = 0x800,
+ kInt64Flag = 0x1000,
+ kUint64Flag = 0x2000,
+ kDoubleFlag = 0x4000,
+ kStringFlag = 0x100000,
+ kCopyFlag = 0x200000,
+ kInlineStrFlag = 0x400000,
+
+ // Initial flags of different types.
+ kNullFlag = kNullType,
+ kTrueFlag = kTrueType | kBoolFlag,
+ kFalseFlag = kFalseType | kBoolFlag,
+ kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+ kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+ kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+ kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+ kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+ kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
+ kConstStringFlag = kStringType | kStringFlag,
+ kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+ kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+ kObjectFlag = kObjectType,
+ kArrayFlag = kArrayType,
+
+ kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
+ };
+
+ static const SizeType kDefaultArrayCapacity = 16;
+ static const SizeType kDefaultObjectCapacity = 16;
+
+ struct String {
+ const Ch* str;
+ SizeType length;
+ unsigned hashcode; //!< reserved
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
+ // (excluding the terminating zero) and store a value to determine the length of the contained
+ // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
+ // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
+ // the string terminator as well. For getting the string length back from that value just use
+ // "MaxSize - str[LenPos]".
+ // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode
+ // inline (for `UTF8`-encoded strings).
+ struct ShortString {
+ enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
+ Ch str[MaxChars];
+
+ inline static bool Usable(SizeType len) { return (MaxSize >= len); }
+ inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); }
+ inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); }
+ }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // By using proper binary layout, retrieval of different integer types do not need conversions.
+ union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+ struct I {
+ int i;
+ char padding[4];
+ }i;
+ struct U {
+ unsigned u;
+ char padding2[4];
+ }u;
+#else
+ struct I {
+ char padding[4];
+ int i;
+ }i;
+ struct U {
+ char padding2[4];
+ unsigned u;
+ }u;
+#endif
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ }; // 8 bytes
+
+ struct Object {
+ Member* members;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ struct Array {
+ GenericValue* elements;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ union Data {
+ String s;
+ ShortString ss;
+ Number n;
+ Object o;
+ Array a;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // Initialize this value as array with initial data, without calling destructor.
+ void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
+ flags_ = kArrayFlag;
+ if (count) {
+ data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
+ std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+ }
+ else
+ data_.a.elements = NULL;
+ data_.a.size = data_.a.capacity = count;
+ }
+
+ //! Initialize this value as object with initial data, without calling destructor.
+ void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
+ flags_ = kObjectFlag;
+ if (count) {
+ data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
+ std::memcpy(data_.o.members, members, count * sizeof(Member));
+ }
+ else
+ data_.o.members = NULL;
+ data_.o.size = data_.o.capacity = count;
+ }
+
+ //! Initialize this value as constant string, without calling destructor.
+ void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
+ flags_ = kConstStringFlag;
+ data_.s.str = s;
+ data_.s.length = s.length;
+ }
+
+ //! Initialize this value as copy string with initial data, without calling destructor.
+ void SetStringRaw(StringRefType s, Allocator& allocator) {
+ Ch* str = NULL;
+ if(ShortString::Usable(s.length)) {
+ flags_ = kShortStringFlag;
+ data_.ss.SetLength(s.length);
+ str = data_.ss.str;
+ } else {
+ flags_ = kCopyStringFlag;
+ data_.s.length = s.length;
+ str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
+ data_.s.str = str;
+ }
+ std::memcpy(str, s, s.length * sizeof(Ch));
+ str[s.length] = '\0';
+ }
+
+ //! Assignment without calling destructor
+ void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ data_ = rhs.data_;
+ flags_ = rhs.flags_;
+ rhs.flags_ = kNullFlag;
+ }
+
+ template <typename SourceAllocator>
+ bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ RAPIDJSON_ASSERT(IsString());
+ RAPIDJSON_ASSERT(rhs.IsString());
+
+ const SizeType len1 = GetStringLength();
+ const SizeType len2 = rhs.GetStringLength();
+ if(len1 != len2) { return false; }
+
+ const Ch* const str1 = GetString();
+ const Ch* const str2 = rhs.GetString();
+ if(str1 == str2) { return true; } // fast path for constant string
+
+ return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
+ }
+
+ Data data_;
+ unsigned flags_;
+};
+
+//! GenericValue with UTF8 encoding
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument
+
+//! A document for parsing JSON text as DOM.
+/*!
+ \note implements Handler concept
+ \tparam Encoding Encoding for both parsing and string storage.
+ \tparam Allocator Allocator for allocating memory for the DOM
+ \tparam StackAllocator Allocator for allocating memory for stack during parsing.
+ \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+
+ //! Constructor
+ /*! \param allocator Optional allocator for allocating memory.
+ \param stackCapacity Optional initial capacity of stack in bytes.
+ \param stackAllocator Optional allocator for allocating memory for stack.
+ */
+ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+ allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+ {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ : ValueType(std::move(rhs)),
+ allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(std::move(rhs.stack_)),
+ parseResult_(rhs.parseResult_)
+ {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+ }
+#endif
+
+ ~GenericDocument() {
+ Destroy();
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ {
+ // The cast to ValueType is necessary here, because otherwise it would
+ // attempt to call GenericValue's templated assignment operator.
+ ValueType::operator=(std::forward<ValueType>(rhs));
+
+ // Calling the destructor here would prematurely call stack_'s destructor
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = std::move(rhs.stack_);
+ parseResult_ = rhs.parseResult_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+
+ return *this;
+ }
+#endif
+
+ //!@name Parse from stream
+ //!@{
+
+ //! Parse JSON text from an input stream (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam SourceEncoding Encoding of input stream
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ ValueType::SetNull(); // Remove existing root if exist
+ GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.GetAllocator());
+ ClearStackOnExit scope(*this);
+ parseResult_ = reader.template Parse<parseFlags>(is, *this);
+ if (parseResult_) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
+ }
+ return *this;
+ }
+
+ //! Parse JSON text from an input stream
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<parseFlags, Encoding, InputStream>(is);
+ }
+
+ //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+ }
+ //!@}
+
+ //!@name Parse in-place from mutable string
+ //!@{
+
+ //! Parse JSON text from a mutable string
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& ParseInsitu(Ch* str) {
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag>(s);
+ }
+
+ //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
+ /*! \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ GenericDocument& ParseInsitu(Ch* str) {
+ return ParseInsitu<kParseDefaultFlags>(str);
+ }
+ //!@}
+
+ //!@name Parse from read-only string
+ //!@{
+
+ //! Parse JSON text from a read-only string (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+ \tparam SourceEncoding Transcoding from input Encoding
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const Ch* str) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ GenericStringStream<SourceEncoding> s(str);
+ return ParseStream<parseFlags, SourceEncoding>(s);
+ }
+
+ //! Parse JSON text from a read-only string
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<parseFlags, Encoding>(str);
+ }
+
+ //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
+ /*! \param str Read-only zero-terminated string to be parsed.
+ */
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<kParseDefaultFlags>(str);
+ }
+ //!@}
+
+ //!@name Handling parse errors
+ //!@{
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseError() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+ //!@}
+
+ //! Get the allocator of this document.
+ Allocator& GetAllocator() { return *allocator_; }
+
+ //! Get the capacity of stack in bytes.
+ size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
+ ~ClearStackOnExit() { d_.ClearStack(); }
+ private:
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ GenericDocument& d_;
+ };
+
+ // callers of the following private Handler functions
+ template <typename,typename,typename> friend class GenericReader; // for parsing
+ template <typename, typename> friend class GenericValue; // for deep copying
+
+ // Implementation of Handler
+ bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
+ bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
+ bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
+
+ bool String(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ return true;
+ }
+
+ bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
+
+ bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount) {
+ typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+ stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
+ return true;
+ }
+
+ bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
+
+ bool EndArray(SizeType elementCount) {
+ ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+ stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+ return true;
+ }
+
+private:
+ //! Prohibit copying
+ GenericDocument(const GenericDocument&);
+ //! Prohibit assignment
+ GenericDocument& operator=(const GenericDocument&);
+
+ void ClearStack() {
+ if (Allocator::kNeedFree)
+ while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+ (stack_.template Pop<ValueType>(1))->~ValueType();
+ else
+ stack_.Clear();
+ stack_.ShrinkToFit();
+ }
+
+ void Destroy() {
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ static const size_t kDefaultStackCapacity = 1024;
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ internal::Stack<StackAllocator> stack_;
+ ParseResult parseResult_;
+};
+
+//! GenericDocument with UTF8 encoding
+typedef GenericDocument<UTF8<> > Document;
+
+// defined here due to the dependency on GenericDocument
+template <typename Encoding, typename Allocator>
+template <typename SourceAllocator>
+inline
+GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
+{
+ switch (rhs.GetType()) {
+ case kObjectType:
+ case kArrayType: { // perform deep copy via SAX Handler
+ GenericDocument<Encoding,Allocator> d(&allocator);
+ rhs.Accept(d);
+ RawAssign(*d.stack_.template Pop<GenericValue>(1));
+ }
+ break;
+ case kStringType:
+ if (rhs.flags_ == kConstStringFlag) {
+ flags_ = rhs.flags_;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ } else {
+ SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+ }
+ break;
+ default: // kNumberType, kTrueType, kFalseType, kNullType
+ flags_ = rhs.flags_;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(_MSC_VER) || defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/dep/rapidjson/rapidjson/encodedstream.h b/dep/rapidjson/rapidjson/encodedstream.h
new file mode 100644
index 00000000000..7c8863fee2f
--- /dev/null
+++ b/dep/rapidjson/rapidjson/encodedstream.h
@@ -0,0 +1,261 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODEDSTREAM_H_
+#define RAPIDJSON_ENCODEDSTREAM_H_
+
+#include "rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Input byte stream wrapper with a statically bound encoding.
+/*!
+ \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+ \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
+*/
+template <typename Encoding, typename InputByteStream>
+class EncodedInputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+ typedef typename Encoding::Ch Ch;
+
+ EncodedInputStream(InputByteStream& is) : is_(is) {
+ current_ = Encoding::TakeBOM(is_);
+ }
+
+ Ch Peek() const { return current_; }
+ Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
+ size_t Tell() const { return is_.Tell(); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ EncodedInputStream(const EncodedInputStream&);
+ EncodedInputStream& operator=(const EncodedInputStream&);
+
+ InputByteStream& is_;
+ Ch current_;
+};
+
+//! Output byte stream wrapper with statically bound encoding.
+/*!
+ \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+ \tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
+*/
+template <typename Encoding, typename OutputByteStream>
+class EncodedOutputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+ typedef typename Encoding::Ch Ch;
+
+ EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
+ if (putBOM)
+ Encoding::PutBOM(os_);
+ }
+
+ void Put(Ch c) { Encoding::Put(os_, c); }
+ void Flush() { os_.Flush(); }
+
+ // Not implemented
+ Ch Peek() const { RAPIDJSON_ASSERT(false); }
+ Ch Take() { RAPIDJSON_ASSERT(false); }
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ EncodedOutputStream(const EncodedOutputStream&);
+ EncodedOutputStream& operator=(const EncodedOutputStream&);
+
+ OutputByteStream& os_;
+};
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+ \tparam CharType Type of character for reading.
+ \tparam InputByteStream type of input byte stream to be wrapped.
+*/
+template <typename CharType, typename InputByteStream>
+class AutoUTFInputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+ typedef CharType Ch;
+
+ //! Constructor.
+ /*!
+ \param is input stream to be wrapped.
+ \param type UTF encoding type if it is not detected from the stream.
+ */
+ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
+ RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+ DetectType();
+ static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
+ takeFunc_ = f[type_];
+ current_ = takeFunc_(*is_);
+ }
+
+ UTFType GetType() const { return type_; }
+ bool HasBOM() const { return hasBOM_; }
+
+ Ch Peek() const { return current_; }
+ Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
+ size_t Tell() const { return is_->Tell(); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ AutoUTFInputStream(const AutoUTFInputStream&);
+ AutoUTFInputStream& operator=(const AutoUTFInputStream&);
+
+ // Detect encoding type with BOM or RFC 4627
+ void DetectType() {
+ // BOM (Byte Order Mark):
+ // 00 00 FE FF UTF-32BE
+ // FF FE 00 00 UTF-32LE
+ // FE FF UTF-16BE
+ // FF FE UTF-16LE
+ // EF BB BF UTF-8
+
+ const unsigned char* c = (const unsigned char *)is_->Peek4();
+ if (!c)
+ return;
+
+ unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
+ hasBOM_ = false;
+ if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+ else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
+
+ // RFC 4627: Section 3
+ // "Since the first two characters of a JSON text will always be ASCII
+ // characters [RFC0020], it is possible to determine whether an octet
+ // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+ // at the pattern of nulls in the first four octets."
+ // 00 00 00 xx UTF-32BE
+ // 00 xx 00 xx UTF-16BE
+ // xx 00 00 00 UTF-32LE
+ // xx 00 xx 00 UTF-16LE
+ // xx xx xx xx UTF-8
+
+ if (!hasBOM_) {
+ unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
+ switch (pattern) {
+ case 0x08: type_ = kUTF32BE; break;
+ case 0x0A: type_ = kUTF16BE; break;
+ case 0x01: type_ = kUTF32LE; break;
+ case 0x05: type_ = kUTF16LE; break;
+ case 0x0F: type_ = kUTF8; break;
+ default: break; // Use type defined by user.
+ }
+ }
+
+ // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+ if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+ if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+ }
+
+ typedef Ch (*TakeFunc)(InputByteStream& is);
+ InputByteStream* is_;
+ UTFType type_;
+ Ch current_;
+ TakeFunc takeFunc_;
+ bool hasBOM_;
+};
+
+//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+ \tparam CharType Type of character for writing.
+ \tparam InputByteStream type of output byte stream to be wrapped.
+*/
+template <typename CharType, typename OutputByteStream>
+class AutoUTFOutputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+ typedef CharType Ch;
+
+ //! Constructor.
+ /*!
+ \param os output stream to be wrapped.
+ \param type UTF encoding type.
+ \param putBOM Whether to write BOM at the beginning of the stream.
+ */
+ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
+ RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+
+ // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+ if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+ if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+
+ static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
+ putFunc_ = f[type_];
+
+ if (putBOM)
+ PutBOM();
+ }
+
+ UTFType GetType() const { return type_; }
+
+ void Put(Ch c) { putFunc_(*os_, c); }
+ void Flush() { os_->Flush(); }
+
+ // Not implemented
+ Ch Peek() const { RAPIDJSON_ASSERT(false); }
+ Ch Take() { RAPIDJSON_ASSERT(false); }
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ AutoUTFOutputStream(const AutoUTFOutputStream&);
+ AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
+
+ void PutBOM() {
+ typedef void (*PutBOMFunc)(OutputByteStream&);
+ static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
+ f[type_](*os_);
+ }
+
+ typedef void (*PutFunc)(OutputByteStream&, Ch);
+
+ OutputByteStream* os_;
+ UTFType type_;
+ PutFunc putFunc_;
+};
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/dep/rapidjson/rapidjson/encodings.h b/dep/rapidjson/rapidjson/encodings.h
new file mode 100644
index 00000000000..90b46ed325b
--- /dev/null
+++ b/dep/rapidjson/rapidjson/encodings.h
@@ -0,0 +1,625 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODINGS_H_
+#define RAPIDJSON_ENCODINGS_H_
+
+#include "rapidjson.h"
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(overflow)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+ \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+ typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
+
+ enum { supportUnicode = 1 }; // or 0 if not supporting unicode
+
+ //! \brief Encode a Unicode codepoint to an output stream.
+ //! \param os Output stream.
+ //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint);
+
+ //! \brief Decode a Unicode codepoint from an input stream.
+ //! \param is Input stream.
+ //! \param codepoint Output of the unicode codepoint.
+ //! \return true if a valid codepoint can be decoded from the stream.
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint);
+
+ //! \brief Validate one Unicode codepoint from an encoded stream.
+ //! \param is Input stream to obtain codepoint.
+ //! \param os Output for copying one codepoint.
+ //! \return true if it is valid.
+ //! \note This function just validating and copying the codepoint without actually decode it.
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os);
+
+ // The following functions are deal with byte streams.
+
+ //! Take a character from input byte stream, skip BOM if exist.
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is);
+
+ //! Take a character from input byte stream.
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is);
+
+ //! Put BOM to output byte stream.
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os);
+
+ //! Put a character to output byte stream.
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+ http://tools.ietf.org/html/rfc3629
+ \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
+ \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct UTF8 {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ else if (codepoint <= 0x7FF) {
+ os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+ }
+ else if (codepoint <= 0xFFFF) {
+ os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
+#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+ Ch c = is.Take();
+ if (!(c & 0x80)) {
+ *codepoint = (unsigned char)c;
+ return true;
+ }
+
+ unsigned char type = GetRange((unsigned char)c);
+ *codepoint = (0xFF >> type) & (unsigned char)c;
+ bool result = true;
+ switch (type) {
+ case 2: TAIL(); return result;
+ case 3: TAIL(); TAIL(); return result;
+ case 4: COPY(); TRANS(0x50); TAIL(); return result;
+ case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+ case 6: TAIL(); TAIL(); TAIL(); return result;
+ case 10: COPY(); TRANS(0x20); TAIL(); return result;
+ case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ default: return false;
+ }
+#undef COPY
+#undef TRANS
+#undef TAIL
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+#define COPY() os.Put(c = is.Take())
+#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+ Ch c;
+ COPY();
+ if (!(c & 0x80))
+ return true;
+
+ bool result = true;
+ switch (GetRange((unsigned char)c)) {
+ case 2: TAIL(); return result;
+ case 3: TAIL(); TAIL(); return result;
+ case 4: COPY(); TRANS(0x50); TAIL(); return result;
+ case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+ case 6: TAIL(); TAIL(); TAIL(); return result;
+ case 10: COPY(); TRANS(0x20); TAIL(); return result;
+ case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ default: return false;
+ }
+#undef COPY
+#undef TRANS
+#undef TAIL
+ }
+
+ static unsigned char GetRange(unsigned char c) {
+ // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+ // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
+ static const unsigned char type[] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+ };
+ return type[c];
+ }
+
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ Ch c = Take(is);
+ if ((unsigned char)c != 0xEFu) return c;
+ c = is.Take();
+ if ((unsigned char)c != 0xBBu) return c;
+ c = is.Take();
+ if ((unsigned char)c != 0xBFu) return c;
+ c = is.Take();
+ return c;
+ }
+
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return is.Take();
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+ http://tools.ietf.org/html/rfc2781
+ \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+ \note implements Encoding concept
+
+ \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+ For streaming, use UTF16LE and UTF16BE, which handle endianness.
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ if (codepoint <= 0xFFFF) {
+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
+ os.Put(static_cast<typename OutputStream::Ch>(codepoint));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+ os.Put((v & 0x3FF) | 0xDC00);
+ }
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+ Ch c = is.Take();
+ if (c < 0xD800 || c > 0xDFFF) {
+ *codepoint = c;
+ return true;
+ }
+ else if (c <= 0xDBFF) {
+ *codepoint = (c & 0x3FF) << 10;
+ c = is.Take();
+ *codepoint |= (c & 0x3FF);
+ *codepoint += 0x10000;
+ return c >= 0xDC00 && c <= 0xDFFF;
+ }
+ return false;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ Ch c;
+ os.Put(c = is.Take());
+ if (c < 0xD800 || c > 0xDFFF)
+ return true;
+ else if (c <= 0xDBFF) {
+ os.Put(c = is.Take());
+ return c >= 0xDC00 && c <= 0xDFFF;
+ }
+ return false;
+ }
+};
+
+//! UTF-16 little endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16LE : UTF16<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return (unsigned short)c == 0xFEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = (unsigned char)is.Take();
+ c |= (unsigned char)is.Take() << 8;
+ return c;
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0xFFu); os.Put(0xFEu);
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(c & 0xFFu);
+ os.Put((c >> 8) & 0xFFu);
+ }
+};
+
+//! UTF-16 big endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16BE : UTF16<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return (unsigned short)c == 0xFEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = (unsigned char)is.Take() << 8;
+ c |= (unsigned char)is.Take();
+ return c;
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0xFEu); os.Put(0xFFu);
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put((c >> 8) & 0xFFu);
+ os.Put(c & 0xFFu);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-32
+ \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+ \note implements Encoding concept
+
+ \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+ For streaming, use UTF32LE and UTF32BE, which handle endianness.
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(codepoint);
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+ Ch c = is.Take();
+ *codepoint = c;
+ return c <= 0x10FFFF;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+ Ch c;
+ os.Put(c = is.Take());
+ return c <= 0x10FFFF;
+ }
+};
+
+//! UTF-32 little endian enocoding.
+template<typename CharType = unsigned>
+struct UTF32LE : UTF32<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = (unsigned char)is.Take();
+ c |= (unsigned char)is.Take() << 8;
+ c |= (unsigned char)is.Take() << 16;
+ c |= (unsigned char)is.Take() << 24;
+ return c;
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(c & 0xFFu);
+ os.Put((c >> 8) & 0xFFu);
+ os.Put((c >> 16) & 0xFFu);
+ os.Put((c >> 24) & 0xFFu);
+ }
+};
+
+//! UTF-32 big endian encoding.
+template<typename CharType = unsigned>
+struct UTF32BE : UTF32<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = (unsigned char)is.Take() << 24;
+ c |= (unsigned char)is.Take() << 16;
+ c |= (unsigned char)is.Take() << 8;
+ c |= (unsigned char)is.Take();
+ return c;
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put((c >> 24) & 0xFFu);
+ os.Put((c >> 16) & 0xFFu);
+ os.Put((c >> 8) & 0xFFu);
+ os.Put(c & 0xFFu);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ASCII
+
+//! ASCII encoding.
+/*! http://en.wikipedia.org/wiki/ASCII
+ \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
+ \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct ASCII {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 0 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x7F);
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ unsigned char c = static_cast<unsigned char>(is.Take());
+ *codepoint = c;
+ return c <= 0X7F;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ unsigned char c = is.Take();
+ os.Put(c);
+ return c <= 0x7F;
+ }
+
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ Ch c = Take(is);
+ return c;
+ }
+
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return is.Take();
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ (void)os;
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// AutoUTF
+
+//! Runtime-specified UTF encoding type of a stream.
+enum UTFType {
+ kUTF8 = 0, //!< UTF-8.
+ kUTF16LE = 1, //!< UTF-16 little endian.
+ kUTF16BE = 2, //!< UTF-16 big endian.
+ kUTF32LE = 3, //!< UTF-32 little endian.
+ kUTF32BE = 4 //!< UTF-32 big endian.
+};
+
+//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
+/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
+*/
+template<typename CharType>
+struct AutoUTF {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 1 };
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+ template<typename OutputStream>
+ RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
+ typedef void (*EncodeFunc)(OutputStream&, unsigned);
+ static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
+ (*f[os.GetType()])(os, codepoint);
+ }
+
+ template <typename InputStream>
+ RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
+ typedef bool (*DecodeFunc)(InputStream&, unsigned*);
+ static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
+ return (*f[is.GetType()])(is, codepoint);
+ }
+
+ template <typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
+ static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
+ return (*f[is.GetType()])(is, os);
+ }
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Transcoder
+
+//! Encoding conversion.
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder {
+ //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ unsigned codepoint;
+ if (!SourceEncoding::Decode(is, &codepoint))
+ return false;
+ TargetEncoding::Encode(os, codepoint);
+ return true;
+ }
+
+ //! Validate one Unicode codepoint from an encoded stream.
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ return Transcode(is, os); // Since source/target encoding is different, must transcode.
+ }
+};
+
+//! Specialization of Transcoder with same source and target encoding.
+template<typename Encoding>
+struct Transcoder<Encoding, Encoding> {
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
+ return true;
+ }
+
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ return Encoding::Validate(is, os); // source/target encoding are the same
+ }
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__) || defined(_MSV_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/dep/rapidjson/rapidjson/error/en.h b/dep/rapidjson/rapidjson/error/en.h
new file mode 100644
index 00000000000..d5f9caab8e9
--- /dev/null
+++ b/dep/rapidjson/rapidjson/error/en.h
@@ -0,0 +1,65 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_EN_H__
+#define RAPIDJSON_ERROR_EN_H__
+
+#include "error.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Maps error code of parsing into error message.
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \param parseErrorCode Error code obtained in parsing.
+ \return the error message.
+ \note User can make a copy of this function for localization.
+ Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
+ switch (parseErrorCode) {
+ case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
+
+ case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
+ case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
+
+ case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
+
+ case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
+ case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
+ case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
+
+ case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
+
+ case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
+ case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
+ case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
+ case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
+ case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
+
+ case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
+ case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
+ case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
+
+ case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
+ case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+
+ default:
+ return RAPIDJSON_ERROR_STRING("Unknown error.");
+ }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ERROR_EN_H__
diff --git a/dep/rapidjson/rapidjson/error/error.h b/dep/rapidjson/rapidjson/error/error.h
new file mode 100644
index 00000000000..f9094fb9594
--- /dev/null
+++ b/dep/rapidjson/rapidjson/error/error.h
@@ -0,0 +1,146 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H__
+#define RAPIDJSON_ERROR_ERROR_H__
+
+#include "../rapidjson.h"
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+ The default character type is \c char.
+ On Windows, user can define this macro as \c TCHAR for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+ By default this conversion macro does nothing.
+ On Windows, user can define this macro as \c _T(x) for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+ kParseErrorNone = 0, //!< No error.
+
+ kParseErrorDocumentEmpty, //!< The document is empty.
+ kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
+
+ kParseErrorValueInvalid, //!< Invalid value.
+
+ kParseErrorObjectMissName, //!< Missing a name for object member.
+ kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
+ kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
+
+ kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
+
+ kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
+ kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
+ kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
+ kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
+ kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
+
+ kParseErrorNumberTooBig, //!< Number too big to be stored in double.
+ kParseErrorNumberMissFraction, //!< Miss fraction part in number.
+ kParseErrorNumberMissExponent, //!< Miss exponent in number.
+
+ kParseErrorTermination, //!< Parsing was terminated.
+ kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse("[42]");
+ if (!ok) {
+ fprintf(stderr, "JSON parse error: %s (%u)",
+ GetParseError_En(ok.Code()), ok.Offset());
+ exit(EXIT_FAILURE);
+ }
+ \endcode
+ \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+
+ //! Default constructor, no error.
+ ParseResult() : code_(kParseErrorNone), offset_(0) {}
+ //! Constructor to set an error.
+ ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
+
+ //! Get the error code.
+ ParseErrorCode Code() const { return code_; }
+ //! Get the error offset, if \ref IsError(), 0 otherwise.
+ size_t Offset() const { return offset_; }
+
+ //! Conversion to \c bool, returns \c true, iff !\ref IsError().
+ operator bool() const { return !IsError(); }
+ //! Whether the result is an error.
+ bool IsError() const { return code_ != kParseErrorNone; }
+
+ bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+ bool operator==(ParseErrorCode code) const { return code_ == code; }
+ friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+
+ //! Reset error code.
+ void Clear() { Set(kParseErrorNone); }
+ //! Update error code and offset.
+ void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
+
+private:
+ ParseErrorCode code_;
+ size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetParseError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ERROR_ERROR_H__
diff --git a/dep/rapidjson/rapidjson/filereadstream.h b/dep/rapidjson/rapidjson/filereadstream.h
new file mode 100644
index 00000000000..3913eb74b0d
--- /dev/null
+++ b/dep/rapidjson/rapidjson/filereadstream.h
@@ -0,0 +1,88 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEREADSTREAM_H_
+#define RAPIDJSON_FILEREADSTREAM_H_
+
+#include "rapidjson.h"
+#include <cstdio>
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! File byte stream for input using fread().
+/*!
+ \note implements Stream concept
+*/
+class FileReadStream {
+public:
+ typedef char Ch; //!< Character type (byte).
+
+ //! Constructor.
+ /*!
+ \param fp File pointer opened for read.
+ \param buffer user-supplied buffer.
+ \param bufferSize size of buffer in bytes. Must >=4 bytes.
+ */
+ FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ RAPIDJSON_ASSERT(bufferSize >= 4);
+ Read();
+ }
+
+ Ch Peek() const { return *current_; }
+ Ch Take() { Ch c = *current_; Read(); return c; }
+ size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ return (current_ + 4 <= bufferLast_) ? current_ : 0;
+ }
+
+private:
+ void Read() {
+ if (current_ < bufferLast_)
+ ++current_;
+ else if (!eof_) {
+ count_ += readCount_;
+ readCount_ = fread(buffer_, 1, bufferSize_, fp_);
+ bufferLast_ = buffer_ + readCount_ - 1;
+ current_ = buffer_;
+
+ if (readCount_ < bufferSize_) {
+ buffer_[readCount_] = '\0';
+ ++bufferLast_;
+ eof_ = true;
+ }
+ }
+ }
+
+ std::FILE* fp_;
+ Ch *buffer_;
+ size_t bufferSize_;
+ Ch *bufferLast_;
+ Ch *current_;
+ size_t readCount_;
+ size_t count_; //!< Number of characters read
+ bool eof_;
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/dep/rapidjson/rapidjson/filewritestream.h b/dep/rapidjson/rapidjson/filewritestream.h
new file mode 100644
index 00000000000..dfb9cbd02a9
--- /dev/null
+++ b/dep/rapidjson/rapidjson/filewritestream.h
@@ -0,0 +1,91 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEWRITESTREAM_H_
+#define RAPIDJSON_FILEWRITESTREAM_H_
+
+#include "rapidjson.h"
+#include <cstdio>
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of C file stream for input using fread().
+/*!
+ \note implements Stream concept
+*/
+class FileWriteStream {
+public:
+ typedef char Ch; //!< Character type. Only support char.
+
+ FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ }
+
+ void Put(char c) {
+ if (current_ >= bufferEnd_)
+ Flush();
+
+ *current_++ = c;
+ }
+
+ void PutN(char c, size_t n) {
+ size_t avail = static_cast<size_t>(bufferEnd_ - current_);
+ while (n > avail) {
+ std::memset(current_, c, avail);
+ current_ += avail;
+ Flush();
+ n -= avail;
+ avail = static_cast<size_t>(bufferEnd_ - current_);
+ }
+
+ if (n > 0) {
+ std::memset(current_, c, n);
+ current_ += n;
+ }
+ }
+
+ void Flush() {
+ if (current_ != buffer_) {
+ fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
+ current_ = buffer_;
+ }
+ }
+
+ // Not implemented
+ char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+ char Take() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ FileWriteStream(const FileWriteStream&);
+ FileWriteStream& operator=(const FileWriteStream&);
+
+ std::FILE* fp_;
+ char *buffer_;
+ char *bufferEnd_;
+ char *current_;
+};
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(FileWriteStream& stream, char c, size_t n) {
+ stream.PutN(c, n);
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/dep/rapidjson/rapidjson/internal/biginteger.h b/dep/rapidjson/rapidjson/internal/biginteger.h
new file mode 100644
index 00000000000..99a30acf613
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/biginteger.h
@@ -0,0 +1,280 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_BIGINTEGER_H_
+#define RAPIDJSON_BIGINTEGER_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h> // for _umul128
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class BigInteger {
+public:
+ typedef uint64_t Type;
+
+ BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
+ std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+ }
+
+ explicit BigInteger(uint64_t u) : count_(1) {
+ digits_[0] = u;
+ }
+
+ BigInteger(const char* decimals, size_t length) : count_(1) {
+ RAPIDJSON_ASSERT(length > 0);
+ digits_[0] = 0;
+ size_t i = 0;
+ const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
+ while (length >= kMaxDigitPerIteration) {
+ AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
+ length -= kMaxDigitPerIteration;
+ i += kMaxDigitPerIteration;
+ }
+
+ if (length > 0)
+ AppendDecimal64(decimals + i, decimals + i + length);
+ }
+
+ BigInteger& operator=(uint64_t u) {
+ digits_[0] = u;
+ count_ = 1;
+ return *this;
+ }
+
+ BigInteger& operator+=(uint64_t u) {
+ Type backup = digits_[0];
+ digits_[0] += u;
+ for (size_t i = 0; i < count_ - 1; i++) {
+ if (digits_[i] >= backup)
+ return *this; // no carry
+ backup = digits_[i + 1];
+ digits_[i + 1] += 1;
+ }
+
+ // Last carry
+ if (digits_[count_ - 1] < backup)
+ PushBack(1);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint64_t u) {
+ if (u == 0) return *this = 0;
+ if (u == 1) return *this;
+ if (*this == 1) return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ uint64_t hi;
+ digits_[i] = MulAdd64(digits_[i], u, k, &hi);
+ k = hi;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint32_t u) {
+ if (u == 0) return *this = 0;
+ if (u == 1) return *this;
+ if (*this == 1) return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ const uint64_t c = digits_[i] >> 32;
+ const uint64_t d = digits_[i] & 0xFFFFFFFF;
+ const uint64_t uc = u * c;
+ const uint64_t ud = u * d;
+ const uint64_t p0 = ud + k;
+ const uint64_t p1 = uc + (p0 >> 32);
+ digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
+ k = p1 >> 32;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator<<=(size_t shift) {
+ if (IsZero() || shift == 0) return *this;
+
+ size_t offset = shift / kTypeBit;
+ size_t interShift = shift % kTypeBit;
+ RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
+
+ if (interShift == 0) {
+ std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
+ count_ += offset;
+ }
+ else {
+ digits_[count_] = 0;
+ for (size_t i = count_; i > 0; i--)
+ digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
+ digits_[offset] = digits_[0] << interShift;
+ count_ += offset;
+ if (digits_[count_])
+ count_++;
+ }
+
+ std::memset(digits_, 0, offset * sizeof(Type));
+
+ return *this;
+ }
+
+ bool operator==(const BigInteger& rhs) const {
+ return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
+ }
+
+ bool operator==(const Type rhs) const {
+ return count_ == 1 && digits_[0] == rhs;
+ }
+
+ BigInteger& MultiplyPow5(unsigned exp) {
+ static const uint32_t kPow5[12] = {
+ 5,
+ 5 * 5,
+ 5 * 5 * 5,
+ 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+ };
+ if (exp == 0) return *this;
+ for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
+ for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
+ if (exp > 0) *this *= kPow5[exp - 1];
+ return *this;
+ }
+
+ // Compute absolute difference of this and rhs.
+ // Assume this != rhs
+ bool Difference(const BigInteger& rhs, BigInteger* out) const {
+ int cmp = Compare(rhs);
+ RAPIDJSON_ASSERT(cmp != 0);
+ const BigInteger *a, *b; // Makes a > b
+ bool ret;
+ if (cmp < 0) { a = &rhs; b = this; ret = true; }
+ else { a = this; b = &rhs; ret = false; }
+
+ Type borrow = 0;
+ for (size_t i = 0; i < a->count_; i++) {
+ Type d = a->digits_[i] - borrow;
+ if (i < b->count_)
+ d -= b->digits_[i];
+ borrow = (d > a->digits_[i]) ? 1 : 0;
+ out->digits_[i] = d;
+ if (d != 0)
+ out->count_ = i + 1;
+ }
+
+ return ret;
+ }
+
+ int Compare(const BigInteger& rhs) const {
+ if (count_ != rhs.count_)
+ return count_ < rhs.count_ ? -1 : 1;
+
+ for (size_t i = count_; i-- > 0;)
+ if (digits_[i] != rhs.digits_[i])
+ return digits_[i] < rhs.digits_[i] ? -1 : 1;
+
+ return 0;
+ }
+
+ size_t GetCount() const { return count_; }
+ Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
+ bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
+
+private:
+ void AppendDecimal64(const char* begin, const char* end) {
+ uint64_t u = ParseUint64(begin, end);
+ if (IsZero())
+ *this = u;
+ else {
+ unsigned exp = static_cast<unsigned>(end - begin);
+ (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
+ }
+ }
+
+ void PushBack(Type digit) {
+ RAPIDJSON_ASSERT(count_ < kCapacity);
+ digits_[count_++] = digit;
+ }
+
+ static uint64_t ParseUint64(const char* begin, const char* end) {
+ uint64_t r = 0;
+ for (const char* p = begin; p != end; ++p) {
+ RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
+ r = r * 10 + (*p - '0');
+ }
+ return r;
+ }
+
+ // Assume a * b + k < 2^128
+ static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t low = _umul128(a, b, outHigh) + k;
+ if (low < k)
+ (*outHigh)++;
+ return low;
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
+ p += k;
+ *outHigh = static_cast<uint64_t>(p >> 64);
+ return static_cast<uint64_t>(p);
+#else
+ const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
+ uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
+ x1 += (x0 >> 32); // can't give carry
+ x1 += x2;
+ if (x1 < x2)
+ x3 += (static_cast<uint64_t>(1) << 32);
+ uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
+ uint64_t hi = x3 + (x1 >> 32);
+
+ lo += k;
+ if (lo < k)
+ hi++;
+ *outHigh = hi;
+ return lo;
+#endif
+ }
+
+ static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
+ static const size_t kCapacity = kBitCount / sizeof(Type);
+ static const size_t kTypeBit = sizeof(Type) * 8;
+
+ Type digits_[kCapacity];
+ size_t count_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_BIGINTEGER_H_
diff --git a/dep/rapidjson/rapidjson/internal/diyfp.h b/dep/rapidjson/rapidjson/internal/diyfp.h
new file mode 100644
index 00000000000..3b6c4238c1f
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/diyfp.h
@@ -0,0 +1,247 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DIYFP_H_
+#define RAPIDJSON_DIYFP_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+struct DiyFp {
+ DiyFp() {}
+
+ DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
+
+ explicit DiyFp(double d) {
+ union {
+ double d;
+ uint64_t u64;
+ } u = { d };
+
+ int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+ uint64_t significand = (u.u64 & kDpSignificandMask);
+ if (biased_e != 0) {
+ f = significand + kDpHiddenBit;
+ e = biased_e - kDpExponentBias;
+ }
+ else {
+ f = significand;
+ e = kDpMinExponent + 1;
+ }
+ }
+
+ DiyFp operator-(const DiyFp& rhs) const {
+ return DiyFp(f - rhs.f, e);
+ }
+
+ DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t h;
+ uint64_t l = _umul128(f, rhs.f, &h);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
+ uint64_t h = static_cast<uint64_t>(p >> 64);
+ uint64_t l = static_cast<uint64_t>(p);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#else
+ const uint64_t M32 = 0xFFFFFFFF;
+ const uint64_t a = f >> 32;
+ const uint64_t b = f & M32;
+ const uint64_t c = rhs.f >> 32;
+ const uint64_t d = rhs.f & M32;
+ const uint64_t ac = a * c;
+ const uint64_t bc = b * c;
+ const uint64_t ad = a * d;
+ const uint64_t bd = b * d;
+ uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+ tmp += 1U << 31; /// mult_round
+ return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+ }
+
+ DiyFp Normalize() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ unsigned long index;
+ _BitScanReverse64(&index, f);
+ return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__) && __GNUC__ >= 4
+ int s = __builtin_clzll(f);
+ return DiyFp(f << s, e - s);
+#else
+ DiyFp res = *this;
+ while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ return res;
+#endif
+ }
+
+ DiyFp NormalizeBoundary() const {
+ DiyFp res = *this;
+ while (!(res.f & (kDpHiddenBit << 1))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+ return res;
+ }
+
+ void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+ DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+ DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
+ mi.f <<= mi.e - pl.e;
+ mi.e = pl.e;
+ *plus = pl;
+ *minus = mi;
+ }
+
+ double ToDouble() const {
+ union {
+ double d;
+ uint64_t u64;
+ }u;
+ const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
+ static_cast<uint64_t>(e + kDpExponentBias);
+ u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
+ return u.d;
+ }
+
+ static const int kDiySignificandSize = 64;
+ static const int kDpSignificandSize = 52;
+ static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+ static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
+ static const int kDpMinExponent = -kDpExponentBias;
+ static const int kDpDenormalExponent = -kDpExponentBias + 1;
+ static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ uint64_t f;
+ int e;
+};
+
+inline DiyFp GetCachedPowerByIndex(size_t index) {
+ // 10^-348, 10^-340, ..., 10^340
+ static const uint64_t kCachedPowers_F[] = {
+ RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
+ RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
+ RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
+ RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+ RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
+ RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+ RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
+ RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
+ RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
+ RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
+ RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+ RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
+ RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+ RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+ RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
+ RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
+ RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
+ RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+ RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
+ RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
+ RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
+ RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
+ RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
+ RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
+ RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+ RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
+ RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
+ RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
+ RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
+ RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
+ RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
+ RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
+ RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
+ RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
+ RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+ RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
+ RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+ RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
+ RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
+ RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
+ RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
+ RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
+ RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+ RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
+ };
+ static const int16_t kCachedPowers_E[] = {
+ -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
+ -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
+ -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
+ -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
+ -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
+ 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
+ 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
+ 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
+ 907, 933, 960, 986, 1013, 1039, 1066
+ };
+ return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+
+inline DiyFp GetCachedPower(int e, int* K) {
+
+ //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+ double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
+ int k = static_cast<int>(dk);
+ if (dk - k > 0.0)
+ k++;
+
+ unsigned index = static_cast<unsigned>((k >> 3) + 1);
+ *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
+
+ return GetCachedPowerByIndex(index);
+}
+
+inline DiyFp GetCachedPower10(int exp, int *outExp) {
+ unsigned index = (exp + 348) / 8;
+ *outExp = -348 + index * 8;
+ return GetCachedPowerByIndex(index);
+ }
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DIYFP_H_
diff --git a/dep/rapidjson/rapidjson/internal/dtoa.h b/dep/rapidjson/rapidjson/internal/dtoa.h
new file mode 100644
index 00000000000..2d8d2e46a3f
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/dtoa.h
@@ -0,0 +1,217 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DTOA_
+#define RAPIDJSON_DTOA_
+
+#include "itoa.h" // GetDigitsLut()
+#include "diyfp.h"
+#include "ieee754.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+ while (rest < wp_w && delta - rest >= ten_kappa &&
+ (rest + ten_kappa < wp_w || /// closer
+ wp_w - rest > rest + ten_kappa - wp_w)) {
+ buffer[len - 1]--;
+ rest += ten_kappa;
+ }
+}
+
+inline unsigned CountDecimalDigit32(uint32_t n) {
+ // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+ if (n < 10) return 1;
+ if (n < 100) return 2;
+ if (n < 1000) return 3;
+ if (n < 10000) return 4;
+ if (n < 100000) return 5;
+ if (n < 1000000) return 6;
+ if (n < 10000000) return 7;
+ if (n < 100000000) return 8;
+ // Will not reach 10 digits in DigitGen()
+ //if (n < 1000000000) return 9;
+ //return 10;
+ return 9;
+}
+
+inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
+ static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+ const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
+ const DiyFp wp_w = Mp - W;
+ uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
+ uint64_t p2 = Mp.f & (one.f - 1);
+ int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+ *len = 0;
+
+ while (kappa > 0) {
+ uint32_t d = 0;
+ switch (kappa) {
+ case 9: d = p1 / 100000000; p1 %= 100000000; break;
+ case 8: d = p1 / 10000000; p1 %= 10000000; break;
+ case 7: d = p1 / 1000000; p1 %= 1000000; break;
+ case 6: d = p1 / 100000; p1 %= 100000; break;
+ case 5: d = p1 / 10000; p1 %= 10000; break;
+ case 4: d = p1 / 1000; p1 %= 1000; break;
+ case 3: d = p1 / 100; p1 %= 100; break;
+ case 2: d = p1 / 10; p1 %= 10; break;
+ case 1: d = p1; p1 = 0; break;
+ default:;
+ }
+ if (d || *len)
+ buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
+ kappa--;
+ uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+ if (tmp <= delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+ return;
+ }
+ }
+
+ // kappa = 0
+ for (;;) {
+ p2 *= 10;
+ delta *= 10;
+ char d = static_cast<char>(p2 >> -one.e);
+ if (d || *len)
+ buffer[(*len)++] = static_cast<char>('0' + d);
+ p2 &= one.f - 1;
+ kappa--;
+ if (p2 < delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
+ return;
+ }
+ }
+}
+
+inline void Grisu2(double value, char* buffer, int* length, int* K) {
+ const DiyFp v(value);
+ DiyFp w_m, w_p;
+ v.NormalizedBoundaries(&w_m, &w_p);
+
+ const DiyFp c_mk = GetCachedPower(w_p.e, K);
+ const DiyFp W = v.Normalize() * c_mk;
+ DiyFp Wp = w_p * c_mk;
+ DiyFp Wm = w_m * c_mk;
+ Wm.f++;
+ Wp.f--;
+ DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+inline char* WriteExponent(int K, char* buffer) {
+ if (K < 0) {
+ *buffer++ = '-';
+ K = -K;
+ }
+
+ if (K >= 100) {
+ *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
+ K %= 100;
+ const char* d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ }
+ else if (K >= 10) {
+ const char* d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ }
+ else
+ *buffer++ = static_cast<char>('0' + static_cast<char>(K));
+
+ return buffer;
+}
+
+inline char* Prettify(char* buffer, int length, int k) {
+ const int kk = length + k; // 10^(kk-1) <= v < 10^kk
+
+ if (length <= kk && kk <= 21) {
+ // 1234e7 -> 12340000000
+ for (int i = length; i < kk; i++)
+ buffer[i] = '0';
+ buffer[kk] = '.';
+ buffer[kk + 1] = '0';
+ return &buffer[kk + 2];
+ }
+ else if (0 < kk && kk <= 21) {
+ // 1234e-2 -> 12.34
+ std::memmove(&buffer[kk + 1], &buffer[kk], length - kk);
+ buffer[kk] = '.';
+ return &buffer[length + 1];
+ }
+ else if (-6 < kk && kk <= 0) {
+ // 1234e-6 -> 0.001234
+ const int offset = 2 - kk;
+ std::memmove(&buffer[offset], &buffer[0], length);
+ buffer[0] = '0';
+ buffer[1] = '.';
+ for (int i = 2; i < offset; i++)
+ buffer[i] = '0';
+ return &buffer[length + offset];
+ }
+ else if (length == 1) {
+ // 1e30
+ buffer[1] = 'e';
+ return WriteExponent(kk - 1, &buffer[2]);
+ }
+ else {
+ // 1234e30 -> 1.234e33
+ std::memmove(&buffer[2], &buffer[1], length - 1);
+ buffer[1] = '.';
+ buffer[length + 1] = 'e';
+ return WriteExponent(kk - 1, &buffer[0 + length + 2]);
+ }
+}
+
+inline char* dtoa(double value, char* buffer) {
+ Double d(value);
+ if (d.IsZero()) {
+ if (d.Sign())
+ *buffer++ = '-'; // -0.0, Issue #289
+ buffer[0] = '0';
+ buffer[1] = '.';
+ buffer[2] = '0';
+ return &buffer[3];
+ }
+ else {
+ if (value < 0) {
+ *buffer++ = '-';
+ value = -value;
+ }
+ int length, K;
+ Grisu2(value, buffer, &length, &K);
+ return Prettify(buffer, length, K);
+ }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DTOA_
diff --git a/dep/rapidjson/rapidjson/internal/ieee754.h b/dep/rapidjson/rapidjson/internal/ieee754.h
new file mode 100644
index 00000000000..e3f03364c60
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/ieee754.h
@@ -0,0 +1,77 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_IEEE754_
+#define RAPIDJSON_IEEE754_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class Double {
+public:
+ Double() {}
+ Double(double d) : d_(d) {}
+ Double(uint64_t u) : u_(u) {}
+
+ double Value() const { return d_; }
+ uint64_t Uint64Value() const { return u_; }
+
+ double NextPositiveDouble() const {
+ RAPIDJSON_ASSERT(!Sign());
+ return Double(u_ + 1).Value();
+ }
+
+ bool Sign() const { return (u_ & kSignMask) != 0; }
+ uint64_t Significand() const { return u_ & kSignificandMask; }
+ int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
+
+ bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
+ bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
+ bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
+ bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
+
+ uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
+ int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
+ uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
+
+ static unsigned EffectiveSignificandSize(int order) {
+ if (order >= -1021)
+ return 53;
+ else if (order <= -1074)
+ return 0;
+ else
+ return order + 1074;
+ }
+
+private:
+ static const int kSignificandSize = 52;
+ static const int kExponentBias = 0x3FF;
+ static const int kDenormalExponent = 1 - kExponentBias;
+ static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
+ static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ union {
+ double d_;
+ uint64_t u_;
+ };
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_IEEE754_
diff --git a/dep/rapidjson/rapidjson/internal/itoa.h b/dep/rapidjson/rapidjson/internal/itoa.h
new file mode 100644
index 00000000000..01a4e7e72d7
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/itoa.h
@@ -0,0 +1,304 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ITOA_
+#define RAPIDJSON_ITOA_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline const char* GetDigitsLut() {
+ static const char cDigitsLut[200] = {
+ '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
+ '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
+ '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
+ '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
+ '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
+ '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
+ '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
+ '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
+ '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
+ '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
+ };
+ return cDigitsLut;
+}
+
+inline char* u32toa(uint32_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+
+ if (value < 10000) {
+ const uint32_t d1 = (value / 100) << 1;
+ const uint32_t d2 = (value % 100) << 1;
+
+ if (value >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ }
+ else if (value < 100000000) {
+ // value = bbbbcccc
+ const uint32_t b = value / 10000;
+ const uint32_t c = value % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ else {
+ // value = aabbbbcccc in decimal
+
+ const uint32_t a = value / 100000000; // 1 to 42
+ value %= 100000000;
+
+ if (a >= 10) {
+ const unsigned i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+ const uint32_t b = value / 10000; // 0 to 9999
+ const uint32_t c = value % 10000; // 0 to 9999
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ return buffer;
+}
+
+inline char* i32toa(int32_t value, char* buffer) {
+ uint32_t u = static_cast<uint32_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u32toa(u, buffer);
+}
+
+inline char* u64toa(uint64_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+ const uint64_t kTen8 = 100000000;
+ const uint64_t kTen9 = kTen8 * 10;
+ const uint64_t kTen10 = kTen8 * 100;
+ const uint64_t kTen11 = kTen8 * 1000;
+ const uint64_t kTen12 = kTen8 * 10000;
+ const uint64_t kTen13 = kTen8 * 100000;
+ const uint64_t kTen14 = kTen8 * 1000000;
+ const uint64_t kTen15 = kTen8 * 10000000;
+ const uint64_t kTen16 = kTen8 * kTen8;
+
+ if (value < kTen8) {
+ uint32_t v = static_cast<uint32_t>(value);
+ if (v < 10000) {
+ const uint32_t d1 = (v / 100) << 1;
+ const uint32_t d2 = (v % 100) << 1;
+
+ if (v >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (v >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (v >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ }
+ else {
+ // value = bbbbcccc
+ const uint32_t b = v / 10000;
+ const uint32_t c = v % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ }
+ else if (value < kTen16) {
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ if (value >= kTen15)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= kTen14)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= kTen13)
+ *buffer++ = cDigitsLut[d2];
+ if (value >= kTen12)
+ *buffer++ = cDigitsLut[d2 + 1];
+ if (value >= kTen11)
+ *buffer++ = cDigitsLut[d3];
+ if (value >= kTen10)
+ *buffer++ = cDigitsLut[d3 + 1];
+ if (value >= kTen9)
+ *buffer++ = cDigitsLut[d4];
+ if (value >= kTen8)
+ *buffer++ = cDigitsLut[d4 + 1];
+
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ }
+ else {
+ const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
+ value %= kTen16;
+
+ if (a < 10)
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+ else if (a < 100) {
+ const uint32_t i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else if (a < 1000) {
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+
+ const uint32_t i = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else {
+ const uint32_t i = (a / 100) << 1;
+ const uint32_t j = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ *buffer++ = cDigitsLut[j];
+ *buffer++ = cDigitsLut[j + 1];
+ }
+
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ }
+
+ return buffer;
+}
+
+inline char* i64toa(int64_t value, char* buffer) {
+ uint64_t u = static_cast<uint64_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u64toa(u, buffer);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ITOA_
diff --git a/dep/rapidjson/rapidjson/internal/meta.h b/dep/rapidjson/rapidjson/internal/meta.h
new file mode 100644
index 00000000000..5a9aaa42866
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/meta.h
@@ -0,0 +1,181 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_META_H_
+#define RAPIDJSON_INTERNAL_META_H_
+
+#include "../rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+#if defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(6334)
+#endif
+
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+#include <type_traits>
+#endif
+
+//@cond RAPIDJSON_INTERNAL
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
+template <typename T> struct Void { typedef void Type; };
+
+///////////////////////////////////////////////////////////////////////////////
+// BoolType, TrueType, FalseType
+//
+template <bool Cond> struct BoolType {
+ static const bool Value = Cond;
+ typedef BoolType Type;
+};
+typedef BoolType<true> TrueType;
+typedef BoolType<false> FalseType;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
+//
+
+template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
+template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
+template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
+template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
+
+template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
+template <> struct AndExprCond<true, true> : TrueType {};
+template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
+template <> struct OrExprCond<false, false> : FalseType {};
+
+template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
+template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
+template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
+template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// AddConst, MaybeAddConst, RemoveConst
+template <typename T> struct AddConst { typedef const T Type; };
+template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
+template <typename T> struct RemoveConst { typedef T Type; };
+template <typename T> struct RemoveConst<const T> { typedef T Type; };
+
+
+///////////////////////////////////////////////////////////////////////////////
+// IsSame, IsConst, IsMoreConst, IsPointer
+//
+template <typename T, typename U> struct IsSame : FalseType {};
+template <typename T> struct IsSame<T, T> : TrueType {};
+
+template <typename T> struct IsConst : FalseType {};
+template <typename T> struct IsConst<const T> : TrueType {};
+
+template <typename CT, typename T>
+struct IsMoreConst
+ : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
+ BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
+
+template <typename T> struct IsPointer : FalseType {};
+template <typename T> struct IsPointer<T*> : TrueType {};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsBaseOf
+//
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+template <typename B, typename D> struct IsBaseOf
+ : BoolType< ::std::is_base_of<B,D>::value> {};
+
+#else // simplified version adopted from Boost
+
+template<typename B, typename D> struct IsBaseOfImpl {
+ RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
+ RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
+
+ typedef char (&Yes)[1];
+ typedef char (&No) [2];
+
+ template <typename T>
+ static Yes Check(const D*, T);
+ static No Check(const B*, int);
+
+ struct Host {
+ operator const B*() const;
+ operator const D*();
+ };
+
+ enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
+};
+
+template <typename B, typename D> struct IsBaseOf
+ : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
+
+#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+
+//////////////////////////////////////////////////////////////////////////
+// EnableIf / DisableIf
+//
+template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
+template <typename T> struct EnableIfCond<false, T> { /* empty */ };
+
+template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
+template <typename T> struct DisableIfCond<true, T> { /* empty */ };
+
+template <typename Condition, typename T = void>
+struct EnableIf : EnableIfCond<Condition::Value, T> {};
+
+template <typename Condition, typename T = void>
+struct DisableIf : DisableIfCond<Condition::Value, T> {};
+
+// SFINAE helpers
+struct SfinaeTag {};
+template <typename T> struct RemoveSfinaeTag;
+template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
+
+#define RAPIDJSON_REMOVEFPTR_(type) \
+ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
+ < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
+
+#define RAPIDJSON_ENABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_DISABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond), \
+ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond), \
+ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+//@endcond
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_META_H_
diff --git a/dep/rapidjson/rapidjson/internal/pow10.h b/dep/rapidjson/rapidjson/internal/pow10.h
new file mode 100644
index 00000000000..02f475d705f
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/pow10.h
@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+ \param n non-negative exponent. Must <= 308.
+ \return 10.0^n
+*/
+inline double Pow10(int n) {
+ static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
+ 1e+0,
+ 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
+ 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+ 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+ 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+ 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+ 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+ 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+ 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+ 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+ 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+ 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+ 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+ 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+ 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+ 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+ };
+ RAPIDJSON_ASSERT(n >= 0 && n <= 308);
+ return e[n];
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_POW10_
diff --git a/dep/rapidjson/rapidjson/internal/stack.h b/dep/rapidjson/rapidjson/internal/stack.h
new file mode 100644
index 00000000000..722d569230b
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/stack.h
@@ -0,0 +1,179 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+ // Optimization note: Do not allocate memory for stack_ in constructor.
+ // Do it lazily when first Push() -> Expand() -> Resize().
+ Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
+ RAPIDJSON_ASSERT(stackCapacity > 0);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack(Stack&& rhs)
+ : allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(rhs.stack_),
+ stackTop_(rhs.stackTop_),
+ stackEnd_(rhs.stackEnd_),
+ initialCapacity_(rhs.initialCapacity_)
+ {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+#endif
+
+ ~Stack() {
+ Destroy();
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack& operator=(Stack&& rhs) {
+ if (&rhs != this)
+ {
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = rhs.stack_;
+ stackTop_ = rhs.stackTop_;
+ stackEnd_ = rhs.stackEnd_;
+ initialCapacity_ = rhs.initialCapacity_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+ return *this;
+ }
+#endif
+
+ void Clear() { stackTop_ = stack_; }
+
+ void ShrinkToFit() {
+ if (Empty()) {
+ // If the stack is empty, completely deallocate the memory.
+ Allocator::Free(stack_);
+ stack_ = 0;
+ stackTop_ = 0;
+ stackEnd_ = 0;
+ }
+ else
+ Resize(GetSize());
+ }
+
+ // Optimization note: try to minimize the size of this function for force inline.
+ // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
+ template<typename T>
+ RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+ // Expand the stack if needed
+ if (stackTop_ + sizeof(T) * count >= stackEnd_)
+ Expand<T>(count);
+
+ T* ret = reinterpret_cast<T*>(stackTop_);
+ stackTop_ += sizeof(T) * count;
+ return ret;
+ }
+
+ template<typename T>
+ T* Pop(size_t count) {
+ RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+ stackTop_ -= count * sizeof(T);
+ return reinterpret_cast<T*>(stackTop_);
+ }
+
+ template<typename T>
+ T* Top() {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+ }
+
+ template<typename T>
+ T* Bottom() { return (T*)stack_; }
+
+ Allocator& GetAllocator() { return *allocator_; }
+ bool Empty() const { return stackTop_ == stack_; }
+ size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
+ size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
+
+private:
+ template<typename T>
+ void Expand(size_t count) {
+ // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
+ size_t newCapacity;
+ if (stack_ == 0) {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ newCapacity = initialCapacity_;
+ } else {
+ newCapacity = GetCapacity();
+ newCapacity += (newCapacity + 1) / 2;
+ }
+ size_t newSize = GetSize() + sizeof(T) * count;
+ if (newCapacity < newSize)
+ newCapacity = newSize;
+
+ Resize(newCapacity);
+ }
+
+ void Resize(size_t newCapacity) {
+ const size_t size = GetSize(); // Backup the current size
+ stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
+ stackTop_ = stack_ + size;
+ stackEnd_ = stack_ + newCapacity;
+ }
+
+ void Destroy() {
+ Allocator::Free(stack_);
+ RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
+ }
+
+ // Prohibit copy constructor & assignment operator.
+ Stack(const Stack&);
+ Stack& operator=(const Stack&);
+
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ char *stack_;
+ char *stackTop_;
+ char *stackEnd_;
+ size_t initialCapacity_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/dep/rapidjson/rapidjson/internal/strfunc.h b/dep/rapidjson/rapidjson/internal/strfunc.h
new file mode 100644
index 00000000000..84405065a27
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/strfunc.h
@@ -0,0 +1,39 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+ \param s Null-terminated input string.
+ \return Number of characters in the string.
+ \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+ const Ch* p = s;
+ while (*p) ++p;
+ return SizeType(p - s);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/dep/rapidjson/rapidjson/internal/strtod.h b/dep/rapidjson/rapidjson/internal/strtod.h
new file mode 100644
index 00000000000..ace65f6773f
--- /dev/null
+++ b/dep/rapidjson/rapidjson/internal/strtod.h
@@ -0,0 +1,270 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRTOD_
+#define RAPIDJSON_STRTOD_
+
+#include "../rapidjson.h"
+#include "ieee754.h"
+#include "biginteger.h"
+#include "diyfp.h"
+#include "pow10.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline double FastPath(double significand, int exp) {
+ if (exp < -308)
+ return 0.0;
+ else if (exp >= 0)
+ return significand * internal::Pow10(exp);
+ else
+ return significand / internal::Pow10(-exp);
+}
+
+inline double StrtodNormalPrecision(double d, int p) {
+ if (p < -308) {
+ // Prevent expSum < -308, making Pow10(p) = 0
+ d = FastPath(d, -308);
+ d = FastPath(d, p + 308);
+ }
+ else
+ d = FastPath(d, p);
+ return d;
+}
+
+template <typename T>
+inline T Min3(T a, T b, T c) {
+ T m = a;
+ if (m > b) m = b;
+ if (m > c) m = c;
+ return m;
+}
+
+inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
+ const Double db(b);
+ const uint64_t bInt = db.IntegerSignificand();
+ const int bExp = db.IntegerExponent();
+ const int hExp = bExp - 1;
+
+ int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
+
+ // Adjust for decimal exponent
+ if (dExp >= 0) {
+ dS_Exp2 += dExp;
+ dS_Exp5 += dExp;
+ }
+ else {
+ bS_Exp2 -= dExp;
+ bS_Exp5 -= dExp;
+ hS_Exp2 -= dExp;
+ hS_Exp5 -= dExp;
+ }
+
+ // Adjust for binary exponent
+ if (bExp >= 0)
+ bS_Exp2 += bExp;
+ else {
+ dS_Exp2 -= bExp;
+ hS_Exp2 -= bExp;
+ }
+
+ // Adjust for half ulp exponent
+ if (hExp >= 0)
+ hS_Exp2 += hExp;
+ else {
+ dS_Exp2 -= hExp;
+ bS_Exp2 -= hExp;
+ }
+
+ // Remove common power of two factor from all three scaled values
+ int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
+ dS_Exp2 -= common_Exp2;
+ bS_Exp2 -= common_Exp2;
+ hS_Exp2 -= common_Exp2;
+
+ BigInteger dS = d;
+ dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2;
+
+ BigInteger bS(bInt);
+ bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2;
+
+ BigInteger hS(1);
+ hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;
+
+ BigInteger delta(0);
+ dS.Difference(bS, &delta);
+
+ return delta.Compare(hS);
+}
+
+inline bool StrtodFast(double d, int p, double* result) {
+ // Use fast path for string-to-double conversion if possible
+ // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
+ if (p > 22 && p < 22 + 16) {
+ // Fast Path Cases In Disguise
+ d *= internal::Pow10(p - 22);
+ p = 22;
+ }
+
+ if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
+ *result = FastPath(d, p);
+ return true;
+ }
+ else
+ return false;
+}
+
+// Compute an approximation and see if it is within 1/2 ULP
+inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
+ uint64_t significand = 0;
+ size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
+ for (; i < length; i++) {
+ if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
+ (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
+ break;
+ significand = significand * 10 + (decimals[i] - '0');
+ }
+
+ if (i < length && decimals[i] >= '5') // Rounding
+ significand++;
+
+ size_t remaining = length - i;
+ const unsigned kUlpShift = 3;
+ const unsigned kUlp = 1 << kUlpShift;
+ int error = (remaining == 0) ? 0 : kUlp / 2;
+
+ DiyFp v(significand, 0);
+ v = v.Normalize();
+ error <<= -v.e;
+
+ const int dExp = (int)decimalPosition - (int)i + exp;
+
+ int actualExp;
+ DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
+ if (actualExp != dExp) {
+ static const DiyFp kPow10[] = {
+ DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
+ DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
+ DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
+ DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
+ DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
+ DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
+ DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
+ };
+ int adjustment = dExp - actualExp - 1;
+ RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
+ v = v * kPow10[adjustment];
+ if (length + adjustment > 19) // has more digits than decimal digits in 64-bit
+ error += kUlp / 2;
+ }
+
+ v = v * cachedPower;
+
+ error += kUlp + (error == 0 ? 0 : 1);
+
+ const int oldExp = v.e;
+ v = v.Normalize();
+ error <<= oldExp - v.e;
+
+ const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
+ unsigned precisionSize = 64 - effectiveSignificandSize;
+ if (precisionSize + kUlpShift >= 64) {
+ unsigned scaleExp = (precisionSize + kUlpShift) - 63;
+ v.f >>= scaleExp;
+ v.e += scaleExp;
+ error = (error >> scaleExp) + 1 + kUlp;
+ precisionSize -= scaleExp;
+ }
+
+ DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
+ const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
+ const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
+ if (precisionBits >= halfWay + error) {
+ rounded.f++;
+ if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
+ rounded.f >>= 1;
+ rounded.e++;
+ }
+ }
+
+ *result = rounded.ToDouble();
+
+ return halfWay - error >= precisionBits || precisionBits >= halfWay + error;
+}
+
+inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+ const BigInteger dInt(decimals, length);
+ const int dExp = (int)decimalPosition - (int)length + exp;
+ Double a(approx);
+ int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
+ if (cmp < 0)
+ return a.Value(); // within half ULP
+ else if (cmp == 0) {
+ // Round towards even
+ if (a.Significand() & 1)
+ return a.NextPositiveDouble();
+ else
+ return a.Value();
+ }
+ else // adjustment
+ return a.NextPositiveDouble();
+}
+
+inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+ RAPIDJSON_ASSERT(d >= 0.0);
+ RAPIDJSON_ASSERT(length >= 1);
+
+ double result;
+ if (StrtodFast(d, p, &result))
+ return result;
+
+ // Trim leading zeros
+ while (*decimals == '0' && length > 1) {
+ length--;
+ decimals++;
+ decimalPosition--;
+ }
+
+ // Trim trailing zeros
+ while (decimals[length - 1] == '0' && length > 1) {
+ length--;
+ decimalPosition--;
+ exp++;
+ }
+
+ // Trim right-most digits
+ const int kMaxDecimalDigit = 780;
+ if ((int)length > kMaxDecimalDigit) {
+ int delta = (int(length) - kMaxDecimalDigit);
+ exp += delta;
+ decimalPosition -= delta;
+ length = kMaxDecimalDigit;
+ }
+
+ // If too small, underflow to zero
+ if (int(length) + exp < -324)
+ return 0.0;
+
+ if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
+ return result;
+
+ // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
+ return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STRTOD_
diff --git a/dep/rapidjson/rapidjson/memorybuffer.h b/dep/rapidjson/rapidjson/memorybuffer.h
new file mode 100644
index 00000000000..2484b2185a8
--- /dev/null
+++ b/dep/rapidjson/rapidjson/memorybuffer.h
@@ -0,0 +1,70 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYBUFFER_H_
+#define RAPIDJSON_MEMORYBUFFER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output byte stream.
+/*!
+ This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
+
+ It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
+
+ Differences between MemoryBuffer and StringBuffer:
+ 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
+ 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
+
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Allocator = CrtAllocator>
+struct GenericMemoryBuffer {
+ typedef char Ch; // byte
+
+ GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() { stack_.ShrinkToFit(); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetBuffer() const {
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericMemoryBuffer<> MemoryBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
+ std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/dep/rapidjson/rapidjson/memorystream.h b/dep/rapidjson/rapidjson/memorystream.h
new file mode 100644
index 00000000000..99feae5d7f8
--- /dev/null
+++ b/dep/rapidjson/rapidjson/memorystream.h
@@ -0,0 +1,61 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYSTREAM_H_
+#define RAPIDJSON_MEMORYSTREAM_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory input byte stream.
+/*!
+ This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
+
+ It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
+
+ Differences between MemoryStream and StringStream:
+ 1. StringStream has encoding but MemoryStream is a byte stream.
+ 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
+ 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
+ \note implements Stream concept
+*/
+struct MemoryStream {
+ typedef char Ch; // byte
+
+ MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
+
+ Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
+ Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
+ size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ return Tell() + 4 <= size_ ? src_ : 0;
+ }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* begin_; //!< Original head of the string.
+ const Ch* end_; //!< End of stream.
+ size_t size_; //!< Size of the stream.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/dep/rapidjson/rapidjson/msinttypes/inttypes.h b/dep/rapidjson/rapidjson/msinttypes/inttypes.h
new file mode 100644
index 00000000000..18111286bf5
--- /dev/null
+++ b/dep/rapidjson/rapidjson/msinttypes/inttypes.h
@@ -0,0 +1,316 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// 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. Neither the name of the product nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by
+// THL A29 Limited ("Tencent Modifications").
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// miloyip: VC supports inttypes.h since VC2013
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+#endif // _MSC_VER >= 1800
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/dep/rapidjson/rapidjson/msinttypes/stdint.h b/dep/rapidjson/rapidjson/msinttypes/stdint.h
new file mode 100644
index 00000000000..a26fff4bf45
--- /dev/null
+++ b/dep/rapidjson/rapidjson/msinttypes/stdint.h
@@ -0,0 +1,300 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// 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. Neither the name of the product nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by
+// THL A29 Limited ("Tencent Modifications").
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+#undef INT8_C
+#undef INT16_C
+#undef INT32_C
+#undef INT64_C
+#undef UINT8_C
+#undef UINT16_C
+#undef UINT32_C
+#undef UINT64_C
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#else // ] _MSC_VER >= 1700 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/dep/rapidjson/rapidjson/prettywriter.h b/dep/rapidjson/rapidjson/prettywriter.h
new file mode 100644
index 00000000000..416dd492e34
--- /dev/null
+++ b/dep/rapidjson/rapidjson/prettywriter.h
@@ -0,0 +1,207 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Writer with indentation and spacing.
+/*!
+ \tparam OutputStream Type of ouptut os.
+ \tparam SourceEncoding Encoding of source string.
+ \tparam TargetEncoding Encoding of output stream.
+ \tparam StackAllocator Type of allocator for allocating memory of stack.
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
+class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> {
+public:
+ typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
+ typedef typename Base::Ch Ch;
+
+ //! Constructor
+ /*! \param os Output stream.
+ \param allocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of stack.
+ */
+ PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+ Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+ //! Set custom indentation.
+ /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
+ \param indentCharCount Number of indent characters for each indentation level.
+ \note The default indentation is 4 spaces.
+ */
+ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+ RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+ indentChar_ = indentChar;
+ indentCharCount_ = indentCharCount;
+ return *this;
+ }
+
+ /*! @name Implementation of Handler
+ \see Handler
+ */
+ //@{
+
+ bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
+ bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
+ bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
+ bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
+ bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
+ bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
+ bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
+
+ bool String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ PrettyPrefix(kStringType);
+ return Base::WriteString(str, length);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool String(const std::basic_string<Ch>& str) {
+ return String(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool StartObject() {
+ PrettyPrefix(kObjectType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+ return Base::WriteStartObject();
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ bool ret = Base::WriteEndObject();
+ (void)ret;
+ RAPIDJSON_ASSERT(ret == true);
+ if (Base::level_stack_.Empty()) // end of json text
+ Base::os_->Flush();
+ return true;
+ }
+
+ bool StartArray() {
+ PrettyPrefix(kArrayType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+ return Base::WriteStartArray();
+ }
+
+ bool EndArray(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ bool ret = Base::WriteEndArray();
+ (void)ret;
+ RAPIDJSON_ASSERT(ret == true);
+ if (Base::level_stack_.Empty()) // end of json text
+ Base::os_->Flush();
+ return true;
+ }
+
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! Simpler but slower overload.
+ bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+ //@}
+protected:
+ void PrettyPrefix(Type type) {
+ (void)type;
+ if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+ typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+ if (level->inArray) {
+ if (level->valueCount > 0) {
+ Base::os_->Put(','); // add comma if it is not the first element in array
+ Base::os_->Put('\n');
+ }
+ else
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ else { // in object
+ if (level->valueCount > 0) {
+ if (level->valueCount % 2 == 0) {
+ Base::os_->Put(',');
+ Base::os_->Put('\n');
+ }
+ else {
+ Base::os_->Put(':');
+ Base::os_->Put(' ');
+ }
+ }
+ else
+ Base::os_->Put('\n');
+
+ if (level->valueCount % 2 == 0)
+ WriteIndent();
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else {
+ RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
+ Base::hasRoot_ = true;
+ }
+ }
+
+ void WriteIndent() {
+ size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+ PutN(*Base::os_, indentChar_, count);
+ }
+
+ Ch indentChar_;
+ unsigned indentCharCount_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ PrettyWriter(const PrettyWriter&);
+ PrettyWriter& operator=(const PrettyWriter&);
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/dep/rapidjson/rapidjson/rapidjson.h b/dep/rapidjson/rapidjson/rapidjson.h
new file mode 100644
index 00000000000..f22130d3cb8
--- /dev/null
+++ b/dep/rapidjson/rapidjson/rapidjson.h
@@ -0,0 +1,654 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+/*!\file rapidjson.h
+ \brief common definitions and configuration
+
+ \see RAPIDJSON_CONFIG
+ */
+
+/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
+ \brief Configuration macros for library features
+
+ Some RapidJSON features are configurable to adapt the library to a wide
+ variety of platforms, environments and usage scenarios. Most of the
+ features can be configured in terms of overriden or predefined
+ preprocessor macros at compile-time.
+
+ Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
+
+ \note These macros should be given on the compiler command-line
+ (where applicable) to avoid inconsistent values when compiling
+ different translation units of a single application.
+ */
+
+#include <cstdlib> // malloc(), realloc(), free(), size_t
+#include <cstring> // memset(), memcpy(), memmove(), memcmp()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_VERSION_STRING
+//
+// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
+//
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+// token stringification
+#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
+#define RAPIDJSON_DO_STRINGIFY(x) #x
+//!@endcond
+
+/*! \def RAPIDJSON_MAJOR_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Major version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_MINOR_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Minor version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_PATCH_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Patch version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_VERSION_STRING
+ \ingroup RAPIDJSON_CONFIG
+ \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
+*/
+#define RAPIDJSON_MAJOR_VERSION 1
+#define RAPIDJSON_MINOR_VERSION 0
+#define RAPIDJSON_PATCH_VERSION 2
+#define RAPIDJSON_VERSION_STRING \
+ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NAMESPACE_(BEGIN|END)
+/*! \def RAPIDJSON_NAMESPACE
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace
+
+ In order to avoid symbol clashes and/or "One Definition Rule" errors
+ between multiple inclusions of (different versions of) RapidJSON in
+ a single binary, users can customize the name of the main RapidJSON
+ namespace.
+
+ In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
+ to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
+ levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
+ RAPIDJSON_NAMESPACE_END need to be defined as well:
+
+ \code
+ // in some .cpp file
+ #define RAPIDJSON_NAMESPACE my::rapidjson
+ #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
+ #define RAPIDJSON_NAMESPACE_END } }
+ #include "rapidjson/..."
+ \endcode
+
+ \see rapidjson
+ */
+/*! \def RAPIDJSON_NAMESPACE_BEGIN
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace (opening expression)
+ \see RAPIDJSON_NAMESPACE
+*/
+/*! \def RAPIDJSON_NAMESPACE_END
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace (closing expression)
+ \see RAPIDJSON_NAMESPACE
+*/
+#ifndef RAPIDJSON_NAMESPACE
+#define RAPIDJSON_NAMESPACE rapidjson
+#endif
+#ifndef RAPIDJSON_NAMESPACE_BEGIN
+#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
+#endif
+#ifndef RAPIDJSON_NAMESPACE_END
+#define RAPIDJSON_NAMESPACE_END }
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+/*! \def RAPIDJSON_NO_INT64DEFINE
+ \ingroup RAPIDJSON_CONFIG
+ \brief Use external 64-bit integer types.
+
+ RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
+ to be available at global scope.
+
+ If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
+ prevent RapidJSON from defining its own types.
+*/
+#ifndef RAPIDJSON_NO_INT64DEFINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#ifdef _MSC_VER
+#include "msinttypes/stdint.h"
+#include "msinttypes/inttypes.h"
+#else
+// Other compilers should have this.
+#include <stdint.h>
+#include <inttypes.h>
+#endif
+//!@endcond
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_INT64DEFINE
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_FORCEINLINE
+
+#ifndef RAPIDJSON_FORCEINLINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && !defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __forceinline
+#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
+#else
+#define RAPIDJSON_FORCEINLINE
+#endif
+//!@endcond
+#endif // RAPIDJSON_FORCEINLINE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
+#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
+
+//! Endianness of the machine.
+/*!
+ \def RAPIDJSON_ENDIAN
+ \ingroup RAPIDJSON_CONFIG
+
+ GCC 4.6 provided macro for detecting endianness of the target machine. But other
+ compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+ \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
+
+ Default detection implemented with reference to
+ \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
+ \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
+*/
+#ifndef RAPIDJSON_ENDIAN
+// Detect with GCC 4.6's macro
+# ifdef __BYTE_ORDER__
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif // __BYTE_ORDER__
+// Detect with GLIBC's endian.h
+# elif defined(__GLIBC__)
+# include <endian.h>
+# if (__BYTE_ORDER == __LITTLE_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif (__BYTE_ORDER == __BIG_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif // __GLIBC__
+// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
+# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+// Detect with architecture macros
+# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
+# define RAPIDJSON_ENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_64BIT
+
+//! Whether using 64-bit architecture
+#ifndef RAPIDJSON_64BIT
+#if defined(__LP64__) || defined(_WIN64)
+#define RAPIDJSON_64BIT 1
+#else
+#define RAPIDJSON_64BIT 0
+#endif
+#endif // RAPIDJSON_64BIT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ALIGN
+
+//! Data alignment of the machine.
+/*! \ingroup RAPIDJSON_CONFIG
+ \param x pointer to align
+
+ Some machines require strict data alignment. Currently the default uses 4 bytes
+ alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.,
+*/
+#ifndef RAPIDJSON_ALIGN
+#if RAPIDJSON_64BIT == 1
+#define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u)
+#else
+#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_UINT64_C2
+
+//! Construct a 64-bit literal by a pair of 32-bit integer.
+/*!
+ 64-bit literal with or without ULL suffix is prone to compiler warnings.
+ UINT64_C() is C macro which cause compilation problems.
+ Use this macro to define 64-bit constants by a pair of 32-bit integer.
+*/
+#ifndef RAPIDJSON_UINT64_C2
+#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+
+/*! \def RAPIDJSON_SIMD
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable SSE2/SSE4.2 optimization.
+
+ RapidJSON supports optimized implementations for some parsing operations
+ based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
+ processors.
+
+ To enable these optimizations, two different symbols can be defined;
+ \code
+ // Enable SSE2 optimization.
+ #define RAPIDJSON_SSE2
+
+ // Enable SSE4.2 optimization.
+ #define RAPIDJSON_SSE42
+ \endcode
+
+ \c RAPIDJSON_SSE42 takes precedence, if both are defined.
+
+ If any of these symbols is defined, RapidJSON defines the macro
+ \c RAPIDJSON_SIMD to indicate the availability of the optimized code.
+*/
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
+ || defined(RAPIDJSON_DOXYGEN_RUNNING)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-provided \c SizeType definition.
+
+ In order to avoid using 32-bit size types for indexing strings and arrays,
+ define this preprocessor symbol and provide the type rapidjson::SizeType
+ before including RapidJSON:
+ \code
+ #define RAPIDJSON_NO_SIZETYPEDEFINE
+ namespace rapidjson { typedef ::std::size_t SizeType; }
+ #include "rapidjson/..."
+ \endcode
+
+ \see rapidjson::SizeType
+*/
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_SIZETYPEDEFINE
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+//! Size type (for string lengths, array sizes, etc.)
+/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
+ instead of using \c size_t. Users may override the SizeType by defining
+ \ref RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+RAPIDJSON_NAMESPACE_END
+#endif
+
+// always import std::size_t to rapidjson namespace
+RAPIDJSON_NAMESPACE_BEGIN
+using std::size_t;
+RAPIDJSON_NAMESPACE_END
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! \ingroup RAPIDJSON_CONFIG
+ By default, rapidjson uses C \c assert() for internal assertions.
+ User can override it by defining RAPIDJSON_ASSERT(x) macro.
+
+ \note Parsing errors are handled and can be customized by the
+ \ref RAPIDJSON_ERRORS APIs.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_STATIC_ASSERT
+
+// Adopt from boost
+#ifndef RAPIDJSON_STATIC_ASSERT
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+RAPIDJSON_NAMESPACE_BEGIN
+template <bool x> struct STATIC_ASSERTION_FAILURE;
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+template<int x> struct StaticAssertTest {};
+RAPIDJSON_NAMESPACE_END
+
+#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
+#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
+#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
+
+#if defined(__GNUC__)
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
+#else
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif
+//!@endcond
+
+/*! \def RAPIDJSON_STATIC_ASSERT
+ \brief (Internal) macro to check for conditions at compile-time
+ \param x compile-time condition
+ \hideinitializer
+ */
+#define RAPIDJSON_STATIC_ASSERT(x) \
+ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
+ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
+ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+// adopted from Boost
+#define RAPIDJSON_VERSION_CODE(x,y,z) \
+ (((x)*100000) + ((y)*100) + (z))
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
+
+#if defined(__GNUC__)
+#define RAPIDJSON_GNUC \
+ RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
+#endif
+
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
+
+#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
+#define RAPIDJSON_DIAG_OFF(x) \
+ RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
+
+// push/pop support in Clang and GCC>=4.6
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
+#else // GCC >= 4.2, < 4.6
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+#endif
+
+#elif defined(_MSC_VER)
+
+// pragma (MSVC specific)
+#define RAPIDJSON_PRAGMA(x) __pragma(x)
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
+
+#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
+
+#else
+
+#define RAPIDJSON_DIAG_OFF(x) /* ignored */
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+
+#endif // RAPIDJSON_DIAG_*
+
+///////////////////////////////////////////////////////////////////////////////
+// C++11 features
+
+#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \
+ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1600)
+
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
+// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#else
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
+#endif
+#endif
+#if RAPIDJSON_HAS_CXX11_NOEXCEPT
+#define RAPIDJSON_NOEXCEPT noexcept
+#else
+#define RAPIDJSON_NOEXCEPT /* noexcept */
+#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+
+// no automatic detection, yet
+#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
+#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
+#endif
+
+//!@endcond
+
+///////////////////////////////////////////////////////////////////////////////
+// new/delete
+
+#ifndef RAPIDJSON_NEW
+///! customization point for global \c new
+#define RAPIDJSON_NEW(x) new x
+#endif
+#ifndef RAPIDJSON_DELETE
+///! customization point for global \c delete
+#define RAPIDJSON_DELETE(x) delete x
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocators and Encodings
+
+#include "allocators.h"
+#include "encodings.h"
+
+/*! \namespace rapidjson
+ \brief main RapidJSON namespace
+ \see RAPIDJSON_NAMESPACE
+*/
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Stream
+
+/*! \class rapidjson::Stream
+ \brief Concept for reading and writing characters.
+
+ For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
+
+ For write-only stream, only need to implement Put() and Flush().
+
+\code
+concept Stream {
+ typename Ch; //!< Character type of the stream.
+
+ //! Read the current character from stream without moving the read cursor.
+ Ch Peek() const;
+
+ //! Read the current character from stream and moving the read cursor to next character.
+ Ch Take();
+
+ //! Get the current read cursor.
+ //! \return Number of characters read from start.
+ size_t Tell();
+
+ //! Begin writing operation at the current read pointer.
+ //! \return The begin writer pointer.
+ Ch* PutBegin();
+
+ //! Write a character.
+ void Put(Ch c);
+
+ //! Flush the buffer.
+ void Flush();
+
+ //! End the writing operation.
+ //! \param begin The begin write pointer returned by PutBegin().
+ //! \return Number of characters written.
+ size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Provides additional information for stream.
+/*!
+ By using traits pattern, this type provides a default configuration for stream.
+ For custom stream, this type can be specialized for other configuration.
+ See TEST(Reader, CustomStringStream) in readertest.cpp for example.
+*/
+template<typename Stream>
+struct StreamTraits {
+ //! Whether to make local copy of stream for optimization during parsing.
+ /*!
+ By default, for safety, streams do not use local copy optimization.
+ Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
+ */
+ enum { copyOptimization = 0 };
+};
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+ for (size_t i = 0; i < n; i++)
+ stream.Put(c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericStringStream<Encoding> > {
+ enum { copyOptimization = 1 };
+};
+
+//! String stream with UTF8 encoding.
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+ \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+ // Read
+ Ch Peek() { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() { return static_cast<size_t>(src_ - head_); }
+
+ // Write
+ void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+
+ Ch* PutBegin() { return dst_ = src_; }
+ size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
+ void Flush() {}
+
+ Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
+ void Pop(size_t count) { dst_ -= count; }
+
+ Ch* src_;
+ Ch* dst_;
+ Ch* head_;
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericInsituStringStream<Encoding> > {
+ enum { copyOptimization = 1 };
+};
+
+//! Insitu string stream with UTF8 encoding.
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+//! Type of JSON value
+enum Type {
+ kNullType = 0, //!< null
+ kFalseType = 1, //!< false
+ kTrueType = 2, //!< true
+ kObjectType = 3, //!< object
+ kArrayType = 4, //!< array
+ kStringType = 5, //!< string
+ kNumberType = 6 //!< number
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/dep/rapidjson/rapidjson/reader.h b/dep/rapidjson/rapidjson/reader.h
new file mode 100644
index 00000000000..c5ecf4be595
--- /dev/null
+++ b/dep/rapidjson/rapidjson/reader.h
@@ -0,0 +1,1452 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+/*! \file reader.h */
+
+#include "rapidjson.h"
+#include "encodings.h"
+#include "internal/meta.h"
+#include "internal/stack.h"
+#include "internal/strtod.h"
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define RAPIDJSON_NOTHING /* deliberately empty */
+#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ if (HasParseError()) { return value; } \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
+//!@endcond
+
+/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
+ \ingroup RAPIDJSON_ERRORS
+ \brief Macro to indicate a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ This macros can be used as a customization point for the internal
+ error handling mechanism of RapidJSON.
+
+ A common usage model is to throw an exception instead of requiring the
+ caller to explicitly check the \ref rapidjson::GenericReader::Parse's
+ return value:
+
+ \code
+ #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
+ throw ParseException(parseErrorCode, #parseErrorCode, offset)
+
+ #include <stdexcept> // std::runtime_error
+ #include "rapidjson/error/error.h" // rapidjson::ParseResult
+
+ struct ParseException : std::runtime_error, rapidjson::ParseResult {
+ ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)
+ : std::runtime_error(msg), ParseResult(code, offset) {}
+ };
+
+ #include "rapidjson/reader.h"
+ \endcode
+
+ \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse
+ */
+#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
+#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
+ SetParseError(parseErrorCode, offset); \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+/*! \def RAPIDJSON_PARSE_ERROR
+ \ingroup RAPIDJSON_ERRORS
+ \brief (Internal) macro to indicate and handle a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.
+
+ \see RAPIDJSON_PARSE_ERROR_NORETURN
+ \hideinitializer
+ */
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+#include "error/error.h" // ParseErrorCode, ParseResult
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kParseDefaultFlags definition.
+
+ User can define this as any \c ParseFlag combinations.
+*/
+#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
+#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
+#endif
+
+//! Combination of parseFlags
+/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
+ */
+enum ParseFlag {
+ kParseNoFlags = 0, //!< No flags are set.
+ kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
+ kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
+ kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
+ kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
+ kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
+ kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*! \class rapidjson::Handler
+ \brief Concept for receiving events from GenericReader upon parsing.
+ The functions return true if no error occurs. If they return false,
+ the event publisher should terminate the process.
+\code
+concept Handler {
+ typename Ch;
+
+ bool Null();
+ bool Bool(bool b);
+ bool Int(int i);
+ bool Uint(unsigned i);
+ bool Int64(int64_t i);
+ bool Uint64(uint64_t i);
+ bool Double(double d);
+ bool String(const Ch* str, SizeType length, bool copy);
+ bool StartObject();
+ bool Key(const Ch* str, SizeType length, bool copy);
+ bool EndObject(SizeType memberCount);
+ bool StartArray();
+ bool EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+ \note implements Handler concept
+*/
+template<typename Encoding = UTF8<>, typename Derived = void>
+struct BaseReaderHandler {
+ typedef typename Encoding::Ch Ch;
+
+ typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;
+
+ bool Default() { return true; }
+ bool Null() { return static_cast<Override&>(*this).Default(); }
+ bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
+ bool Int(int) { return static_cast<Override&>(*this).Default(); }
+ bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
+ bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Double(double) { return static_cast<Override&>(*this).Default(); }
+ bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
+ bool StartObject() { return static_cast<Override&>(*this).Default(); }
+ bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
+ bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
+ bool StartArray() { return static_cast<Override&>(*this).Default(); }
+ bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamLocalCopy
+
+namespace internal {
+
+template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
+class StreamLocalCopy;
+
+//! Do copy optimization.
+template<typename Stream>
+class StreamLocalCopy<Stream, 1> {
+public:
+ StreamLocalCopy(Stream& original) : s(original), original_(original) {}
+ ~StreamLocalCopy() { original_ = s; }
+
+ Stream s;
+
+private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+
+ Stream& original_;
+};
+
+//! Keep reference.
+template<typename Stream>
+class StreamLocalCopy<Stream, 0> {
+public:
+ StreamLocalCopy(Stream& original) : s(original) {}
+
+ Stream& s;
+
+private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param is A input stream for skipping white spaces.
+ \note This function has SSE2/SSE4.2 specialization.
+*/
+template<typename InputStream>
+void SkipWhitespace(InputStream& is) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // The rest of string using SIMD
+ static const char whitespace[16] = " \n\r\t";
+ const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]);
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128((const __m128i *)p);
+ const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
+ if (r != 0) { // some of characters is non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // The rest of string
+ static const char whitespaces[4][17] = {
+ " ",
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
+ "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
+
+ const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
+ const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
+ const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
+ const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128((const __m128i *)p);
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = (unsigned short)~_mm_movemask_epi8(x);
+ if (r != 0) { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template<> inline void SkipWhitespace(InsituStringStream& is) {
+ is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
+}
+
+//! Template function specialization for StringStream
+template<> inline void SkipWhitespace(StringStream& is) {
+ is.src_ = SkipWhitespace_SIMD(is.src_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
+ object implementing Handler concept.
+
+ It needs to allocate a stack for storing a single decoded string during
+ non-destructive parsing.
+
+ For in-situ parsing, the decoded string is directly written to the source
+ text string, no temporary buffer is required.
+
+ A GenericReader object can be reused for parsing multiple JSON text.
+
+ \tparam SourceEncoding Encoding of the input stream.
+ \tparam TargetEncoding Encoding of the parse output.
+ \tparam StackAllocator Allocator type for stack.
+*/
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>
+class GenericReader {
+public:
+ typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
+
+ //! Constructor.
+ /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+ \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
+ */
+ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
+
+ //! Parse JSON text.
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept.
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ if (parseFlags & kParseIterativeFlag)
+ return IterativeParse<parseFlags>(is, handler);
+
+ parseResult_.Clear();
+
+ ClearStackOnExit scope(*this);
+
+ SkipWhitespace(is);
+
+ if (is.Peek() == '\0') {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+ else {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (!(parseFlags & kParseStopWhenDoneFlag)) {
+ SkipWhitespace(is);
+
+ if (is.Peek() != '\0') {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+ }
+ }
+
+ return parseResult_;
+ }
+
+ //! Parse JSON text (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ return Parse<kParseDefaultFlags>(is, handler);
+ }
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+protected:
+ void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ GenericReader(const GenericReader&);
+ GenericReader& operator=(const GenericReader&);
+
+ void ClearStack() { stack_.Clear(); }
+
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
+ ~ClearStackOnExit() { r_.ClearStack(); }
+ private:
+ GenericReader& r_;
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ };
+
+ // Parse object: { string : value, ... }
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseObject(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '{');
+ is.Take(); // Skip '{'
+
+ if (!handler.StartObject())
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespace(is);
+
+ if (is.Peek() == '}') {
+ is.Take();
+ if (!handler.EndObject(0)) // empty object
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType memberCount = 0;;) {
+ if (is.Peek() != '"')
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+
+ ParseString<parseFlags>(is, handler, true);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespace(is);
+
+ if (is.Take() != ':')
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+
+ SkipWhitespace(is);
+
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespace(is);
+
+ ++memberCount;
+
+ switch (is.Take()) {
+ case ',': SkipWhitespace(is); break;
+ case '}':
+ if (!handler.EndObject(memberCount))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
+ }
+ }
+ }
+
+ // Parse array: [ value, ... ]
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseArray(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '[');
+ is.Take(); // Skip '['
+
+ if (!handler.StartArray())
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespace(is);
+
+ if (is.Peek() == ']') {
+ is.Take();
+ if (!handler.EndArray(0)) // empty array
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType elementCount = 0;;) {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++elementCount;
+ SkipWhitespace(is);
+
+ switch (is.Take()) {
+ case ',': SkipWhitespace(is); break;
+ case ']':
+ if (!handler.EndArray(elementCount))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
+ }
+ }
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNull(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'n');
+ is.Take();
+
+ if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') {
+ if (!handler.Null())
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseTrue(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 't');
+ is.Take();
+
+ if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') {
+ if (!handler.Bool(true))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseFalse(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'f');
+ is.Take();
+
+ if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') {
+ if (!handler.Bool(false))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
+ }
+
+ // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ template<typename InputStream>
+ unsigned ParseHex4(InputStream& is) {
+ unsigned codepoint = 0;
+ for (int i = 0; i < 4; i++) {
+ Ch c = is.Take();
+ codepoint <<= 4;
+ codepoint += static_cast<unsigned>(c);
+ if (c >= '0' && c <= '9')
+ codepoint -= '0';
+ else if (c >= 'A' && c <= 'F')
+ codepoint -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ codepoint -= 'a' - 10;
+ else {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
+ }
+ }
+ return codepoint;
+ }
+
+ template <typename CharType>
+ class StackStream {
+ public:
+ typedef CharType Ch;
+
+ StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
+ RAPIDJSON_FORCEINLINE void Put(Ch c) {
+ *stack_.template Push<Ch>() = c;
+ ++length_;
+ }
+ size_t Length() const { return length_; }
+ Ch* Pop() {
+ return stack_.template Pop<Ch>(length_);
+ }
+
+ private:
+ StackStream(const StackStream&);
+ StackStream& operator=(const StackStream&);
+
+ internal::Stack<StackAllocator>& stack_;
+ SizeType length_;
+ };
+
+ // Parse string and generate String event. Different code paths for kParseInsituFlag.
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ bool success = false;
+ if (parseFlags & kParseInsituFlag) {
+ typename InputStream::Ch *head = s.PutBegin();
+ ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ size_t length = s.PutEnd(head) - 1;
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head;
+ success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
+ }
+ else {
+ StackStream<typename TargetEncoding::Ch> stackStream(stack_);
+ ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
+ const typename TargetEncoding::Ch* const str = stackStream.Pop();
+ success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
+ }
+ if (!success)
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
+ }
+
+ // Parse string to an output is
+ // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
+ template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ static const char escape[256] = {
+ Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+ Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
+ 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
+ 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
+ };
+#undef Z16
+//!@endcond
+
+ RAPIDJSON_ASSERT(is.Peek() == '\"');
+ is.Take(); // Skip '\"'
+
+ for (;;) {
+ Ch c = is.Peek();
+ if (c == '\\') { // Escape
+ is.Take();
+ Ch e = is.Take();
+ if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {
+ os.Put(escape[(unsigned char)e]);
+ }
+ else if (e == 'u') { // Unicode
+ unsigned codepoint = ParseHex4(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
+ // Handle UTF-16 surrogate pair
+ if (is.Take() != '\\' || is.Take() != 'u')
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
+ unsigned codepoint2 = ParseHex4(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+ }
+ TEncoding::Encode(os, codepoint);
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
+ }
+ else if (c == '"') { // Closing double quote
+ is.Take();
+ os.Put('\0'); // null-terminate the string
+ return;
+ }
+ else if (c == '\0')
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
+ else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
+ else {
+ if (parseFlags & kParseValidateEncodingFlag ?
+ !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
+ !Transcoder<SEncoding, TEncoding>::Transcode(is, os))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
+ }
+ }
+ }
+
+ template<typename InputStream, bool backup>
+ class NumberStream;
+
+ template<typename InputStream>
+ class NumberStream<InputStream, false> {
+ public:
+ NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
+ RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
+ RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
+ size_t Tell() { return is.Tell(); }
+ size_t Length() { return 0; }
+ const char* Pop() { return 0; }
+
+ protected:
+ NumberStream& operator=(const NumberStream&);
+
+ InputStream& is;
+ };
+
+ template<typename InputStream>
+ class NumberStream<InputStream, true> : public NumberStream<InputStream, false> {
+ typedef NumberStream<InputStream, false> Base;
+ public:
+ NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch TakePush() {
+ stackStream.Put((char)Base::is.Peek());
+ return Base::is.Take();
+ }
+
+ size_t Length() { return stackStream.Length(); }
+
+ const char* Pop() {
+ stackStream.Put('\0');
+ return stackStream.Pop();
+ }
+
+ private:
+ StackStream<char> stackStream;
+ };
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNumber(InputStream& is, Handler& handler) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
+
+ // Parse minus
+ bool minus = false;
+ if (s.Peek() == '-') {
+ minus = true;
+ s.Take();
+ }
+
+ // Parse int: zero / ( digit1-9 *DIGIT )
+ unsigned i = 0;
+ uint64_t i64 = 0;
+ bool use64bit = false;
+ int significandDigit = 0;
+ if (s.Peek() == '0') {
+ i = 0;
+ s.TakePush();
+ }
+ else if (s.Peek() >= '1' && s.Peek() <= '9') {
+ i = static_cast<unsigned>(s.TakePush() - '0');
+
+ if (minus)
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i >= 214748364) { // 2^31 = 2147483648
+ if (i != 214748364 || s.Peek() > '8') {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i >= 429496729) { // 2^32 - 1 = 4294967295
+ if (i != 429496729 || s.Peek() > '5') {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+
+ // Parse 64bit int
+ bool useDouble = false;
+ double d = 0.0;
+ if (use64bit) {
+ if (minus)
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808
+ if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {
+ d = i64;
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615
+ if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') {
+ d = i64;
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+
+ // Force double for big integer
+ if (useDouble) {
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
+ d = d * 10 + (s.TakePush() - '0');
+ }
+ }
+
+ // Parse frac = decimal-point 1*DIGIT
+ int expFrac = 0;
+ size_t decimalPosition;
+ if (s.Peek() == '.') {
+ s.Take();
+ decimalPosition = s.Length();
+
+ if (!(s.Peek() >= '0' && s.Peek() <= '9'))
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
+
+ if (!useDouble) {
+#if RAPIDJSON_64BIT
+ // Use i64 to store significand in 64-bit architecture
+ if (!use64bit)
+ i64 = i;
+
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
+ break;
+ else {
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ --expFrac;
+ if (i64 != 0)
+ significandDigit++;
+ }
+ }
+
+ d = (double)i64;
+#else
+ // Use double to store significand in 32-bit architecture
+ d = use64bit ? (double)i64 : (double)i;
+#endif
+ useDouble = true;
+ }
+
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (significandDigit < 17) {
+ d = d * 10.0 + (s.TakePush() - '0');
+ --expFrac;
+ if (d > 0.0)
+ significandDigit++;
+ }
+ else
+ s.TakePush();
+ }
+ }
+ else
+ decimalPosition = s.Length(); // decimal position at the end of integer.
+
+ // Parse exp = e [ minus / plus ] 1*DIGIT
+ int exp = 0;
+ if (s.Peek() == 'e' || s.Peek() == 'E') {
+ if (!useDouble) {
+ d = use64bit ? i64 : i;
+ useDouble = true;
+ }
+ s.Take();
+
+ bool expMinus = false;
+ if (s.Peek() == '+')
+ s.Take();
+ else if (s.Peek() == '-') {
+ s.Take();
+ expMinus = true;
+ }
+
+ if (s.Peek() >= '0' && s.Peek() <= '9') {
+ exp = s.Take() - '0';
+ if (expMinus) {
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ exp = exp * 10 + (s.Take() - '0');
+ if (exp >= 214748364) { // Issue #313: prevent overflow exponent
+ while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent
+ s.Take();
+ }
+ }
+ }
+ else { // positive exp
+ int maxExp = 308 - expFrac;
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ exp = exp * 10 + (s.Take() - '0');
+ if (exp > maxExp)
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
+ }
+ }
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
+
+ if (expMinus)
+ exp = -exp;
+ }
+
+ // Finish parsing, call event according to the type of number.
+ bool cont = true;
+ size_t length = s.Length();
+ const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
+
+ if (useDouble) {
+ int p = exp + expFrac;
+ if (parseFlags & kParseFullPrecisionFlag)
+ d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
+ else
+ d = internal::StrtodNormalPrecision(d, p);
+
+ cont = handler.Double(minus ? -d : d);
+ }
+ else {
+ if (use64bit) {
+ if (minus)
+ cont = handler.Int64(-(int64_t)i64);
+ else
+ cont = handler.Uint64(i64);
+ }
+ else {
+ if (minus)
+ cont = handler.Int(-(int)i);
+ else
+ cont = handler.Uint(i);
+ }
+ }
+ if (!cont)
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
+ }
+
+ // Parse any JSON value
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseValue(InputStream& is, Handler& handler) {
+ switch (is.Peek()) {
+ case 'n': ParseNull <parseFlags>(is, handler); break;
+ case 't': ParseTrue <parseFlags>(is, handler); break;
+ case 'f': ParseFalse <parseFlags>(is, handler); break;
+ case '"': ParseString<parseFlags>(is, handler); break;
+ case '{': ParseObject<parseFlags>(is, handler); break;
+ case '[': ParseArray <parseFlags>(is, handler); break;
+ default : ParseNumber<parseFlags>(is, handler);
+ }
+ }
+
+ // Iterative Parsing
+
+ // States
+ enum IterativeParsingState {
+ IterativeParsingStartState = 0,
+ IterativeParsingFinishState,
+ IterativeParsingErrorState,
+
+ // Object states
+ IterativeParsingObjectInitialState,
+ IterativeParsingMemberKeyState,
+ IterativeParsingKeyValueDelimiterState,
+ IterativeParsingMemberValueState,
+ IterativeParsingMemberDelimiterState,
+ IterativeParsingObjectFinishState,
+
+ // Array states
+ IterativeParsingArrayInitialState,
+ IterativeParsingElementState,
+ IterativeParsingElementDelimiterState,
+ IterativeParsingArrayFinishState,
+
+ // Single value state
+ IterativeParsingValueState,
+
+ cIterativeParsingStateCount
+ };
+
+ // Tokens
+ enum Token {
+ LeftBracketToken = 0,
+ RightBracketToken,
+
+ LeftCurlyBracketToken,
+ RightCurlyBracketToken,
+
+ CommaToken,
+ ColonToken,
+
+ StringToken,
+ FalseToken,
+ TrueToken,
+ NullToken,
+ NumberToken,
+
+ kTokenCount
+ };
+
+ RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define N NumberToken
+#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N
+ // Maps from ASCII to Token
+ static const unsigned char tokenMap[256] = {
+ N16, // 00~0F
+ N16, // 10~1F
+ N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F
+ N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F
+ N16, // 40~4F
+ N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F
+ N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F
+ N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F
+ N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF
+ };
+#undef N
+#undef N16
+//!@endcond
+
+ if (sizeof(Ch) == 1 || unsigned(c) < 256)
+ return (Token)tokenMap[(unsigned char)c];
+ else
+ return NumberToken;
+ }
+
+ RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
+ // current state x one lookahead token -> new state
+ static const char G[cIterativeParsingStateCount][kTokenCount] = {
+ // Start
+ {
+ IterativeParsingArrayInitialState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingValueState, // String
+ IterativeParsingValueState, // False
+ IterativeParsingValueState, // True
+ IterativeParsingValueState, // Null
+ IterativeParsingValueState // Number
+ },
+ // Finish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Error(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // ObjectInitial
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberKey
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingKeyValueDelimiterState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // KeyValueDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberValueState, // String
+ IterativeParsingMemberValueState, // False
+ IterativeParsingMemberValueState, // True
+ IterativeParsingMemberValueState, // Null
+ IterativeParsingMemberValueState // Number
+ },
+ // MemberValue
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingMemberDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberDelimiter
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ObjectFinish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // ArrayInitial
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element state)
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // Element
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingElementDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ElementDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element state)
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // ArrayFinish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Single Value (sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ }
+ }; // End of G
+
+ return (IterativeParsingState)G[state][token];
+ }
+
+ // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
+ // May return a new state on state pop.
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
+ (void)token;
+
+ switch (dst) {
+ case IterativeParsingErrorState:
+ return dst;
+
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingArrayInitialState:
+ {
+ // Push the state(Element or MemeberValue) if we are nested in another array or value of member.
+ // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.
+ IterativeParsingState n = src;
+ if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)
+ n = IterativeParsingElementState;
+ else if (src == IterativeParsingKeyValueDelimiterState)
+ n = IterativeParsingMemberValueState;
+ // Push current state.
+ *stack_.template Push<SizeType>(1) = n;
+ // Initialize and push the member/element count.
+ *stack_.template Push<SizeType>(1) = 0;
+ // Call handler
+ bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return dst;
+ }
+ }
+
+ case IterativeParsingMemberKeyState:
+ ParseString<parseFlags>(is, handler, true);
+ if (HasParseError())
+ return IterativeParsingErrorState;
+ else
+ return dst;
+
+ case IterativeParsingKeyValueDelimiterState:
+ RAPIDJSON_ASSERT(token == ColonToken);
+ is.Take();
+ return dst;
+
+ case IterativeParsingMemberValueState:
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingElementState:
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingMemberDelimiterState:
+ case IterativeParsingElementDelimiterState:
+ is.Take();
+ // Update member/element count.
+ *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
+ return dst;
+
+ case IterativeParsingObjectFinishState:
+ {
+ // Get member count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the object is not empty, count the last member.
+ if (src == IterativeParsingMemberValueState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndObject(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return n;
+ }
+ }
+
+ case IterativeParsingArrayFinishState:
+ {
+ // Get element count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the array is not empty, count the last element.
+ if (src == IterativeParsingElementState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndArray(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return n;
+ }
+ }
+
+ default:
+ // This branch is for IterativeParsingValueState actually.
+ // Use `default:` rather than
+ // `case IterativeParsingValueState:` is for code coverage.
+
+ // The IterativeParsingStartState is not enumerated in this switch-case.
+ // It is impossible for that case. And it can be caught by following assertion.
+
+ // The IterativeParsingFinishState is not enumerated in this switch-case either.
+ // It is a "derivative" state which cannot triggered from Predict() directly.
+ // Therefore it cannot happen here. And it can be caught by following assertion.
+ RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
+
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return IterativeParsingFinishState;
+ }
+ }
+
+ template <typename InputStream>
+ void HandleError(IterativeParsingState src, InputStream& is) {
+ if (HasParseError()) {
+ // Error flag has been set.
+ return;
+ }
+
+ switch (src) {
+ case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
+ case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+ case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+ case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
+ case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
+ default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+ }
+ }
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult IterativeParse(InputStream& is, Handler& handler) {
+ parseResult_.Clear();
+ ClearStackOnExit scope(*this);
+ IterativeParsingState state = IterativeParsingStartState;
+
+ SkipWhitespace(is);
+ while (is.Peek() != '\0') {
+ Token t = Tokenize(is.Peek());
+ IterativeParsingState n = Predict(state, t);
+ IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
+
+ if (d == IterativeParsingErrorState) {
+ HandleError(state, is);
+ break;
+ }
+
+ state = d;
+
+ // Do not further consume streams if a root JSON has been parsed.
+ if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
+ break;
+
+ SkipWhitespace(is);
+ }
+
+ // Handle the end of file.
+ if (state != IterativeParsingFinishState)
+ HandleError(state, is);
+
+ return parseResult_;
+ }
+
+ static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
+ ParseResult parseResult_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/dep/rapidjson/rapidjson/stringbuffer.h b/dep/rapidjson/rapidjson/stringbuffer.h
new file mode 100644
index 00000000000..1c9c80b7993
--- /dev/null
+++ b/dep/rapidjson/rapidjson/stringbuffer.h
@@ -0,0 +1,93 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "rapidjson.h"
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+#include "internal/stack.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output stream.
+/*!
+ \tparam Encoding Encoding of the stream.
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericStringBuffer {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
+ GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
+ if (&rhs != this)
+ stack_ = std::move(rhs.stack_);
+ return *this;
+ }
+#endif
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.ShrinkToFit();
+ stack_.template Pop<Ch>(1);
+ }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetString() const {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.template Pop<Ch>(1);
+
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ GenericStringBuffer(const GenericStringBuffer&);
+ GenericStringBuffer& operator=(const GenericStringBuffer&);
+};
+
+//! String buffer with UTF8 encoding
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+ std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/dep/rapidjson/rapidjson/writer.h b/dep/rapidjson/rapidjson/writer.h
new file mode 100644
index 00000000000..e1eea38b987
--- /dev/null
+++ b/dep/rapidjson/rapidjson/writer.h
@@ -0,0 +1,395 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include "internal/dtoa.h"
+#include "internal/itoa.h"
+#include "stringbuffer.h"
+#include <new> // placement new
+
+#if RAPIDJSON_HAS_STDSTRING
+#include <string>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+ It generates JSON text by events to an output os.
+
+ User may programmatically calls the functions of a writer to generate JSON text.
+
+ On the other side, a writer can also be passed to objects that generates events,
+
+ for example Reader::Parse() and Document::Accept().
+
+ \tparam OutputStream Type of output stream.
+ \tparam SourceEncoding Encoding of source string.
+ \tparam TargetEncoding Encoding of output stream.
+ \tparam StackAllocator Type of allocator for allocating memory of stack.
+ \note implements Handler concept
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
+class Writer {
+public:
+ typedef typename SourceEncoding::Ch Ch;
+
+ //! Constructor
+ /*! \param os Output stream.
+ \param stackAllocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of stack.
+ */
+ explicit
+ Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
+
+ explicit
+ Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
+
+ //! Reset the writer with a new stream.
+ /*!
+ This function reset the writer with a new stream and default settings,
+ in order to make a Writer object reusable for output multiple JSONs.
+
+ \param os New output stream.
+ \code
+ Writer<OutputStream> writer(os1);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+
+ writer.Reset(os2);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+ \endcode
+ */
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ hasRoot_ = false;
+ level_stack_.Clear();
+ }
+
+ //! Checks whether the output is a complete JSON.
+ /*!
+ A complete JSON has a complete root object or array.
+ */
+ bool IsComplete() const {
+ return hasRoot_ && level_stack_.Empty();
+ }
+
+ /*!@name Implementation of Handler
+ \see Handler
+ */
+ //@{
+
+ bool Null() { Prefix(kNullType); return WriteNull(); }
+ bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
+ bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
+ bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
+ bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
+ bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
+
+ //! Writes the given \c double value to the stream
+ /*!
+ \param d The value to be written.
+ \return Whether it is succeed.
+ */
+ bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
+
+ bool String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ Prefix(kStringType);
+ return WriteString(str, length);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool String(const std::basic_string<Ch>& str) {
+ return String(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool StartObject() {
+ Prefix(kObjectType);
+ new (level_stack_.template Push<Level>()) Level(false);
+ return WriteStartObject();
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ bool ret = WriteEndObject();
+ if (level_stack_.Empty()) // end of json text
+ os_->Flush();
+ return ret;
+ }
+
+ bool StartArray() {
+ Prefix(kArrayType);
+ new (level_stack_.template Push<Level>()) Level(true);
+ return WriteStartArray();
+ }
+
+ bool EndArray(SizeType elementCount = 0) {
+ (void)elementCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ bool ret = WriteEndArray();
+ if (level_stack_.Empty()) // end of json text
+ os_->Flush();
+ return ret;
+ }
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! Simpler but slower overload.
+ bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+ //@}
+
+protected:
+ //! Information for each nested level
+ struct Level {
+ Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
+ size_t valueCount; //!< number of values in this level
+ bool inArray; //!< true if in array, otherwise in object
+ };
+
+ static const size_t kDefaultLevelDepth = 32;
+
+ bool WriteNull() {
+ os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
+ }
+
+ bool WriteBool(bool b) {
+ if (b) {
+ os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
+ }
+ else {
+ os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
+ }
+ return true;
+ }
+
+ bool WriteInt(int i) {
+ char buffer[11];
+ const char* end = internal::i32toa(i, buffer);
+ for (const char* p = buffer; p != end; ++p)
+ os_->Put(*p);
+ return true;
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ const char* end = internal::u32toa(u, buffer);
+ for (const char* p = buffer; p != end; ++p)
+ os_->Put(*p);
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ char buffer[21];
+ const char* end = internal::i64toa(i64, buffer);
+ for (const char* p = buffer; p != end; ++p)
+ os_->Put(*p);
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char* end = internal::u64toa(u64, buffer);
+ for (char* p = buffer; p != end; ++p)
+ os_->Put(*p);
+ return true;
+ }
+
+ bool WriteDouble(double d) {
+ char buffer[25];
+ char* end = internal::dtoa(d, buffer);
+ for (char* p = buffer; p != end; ++p)
+ os_->Put(*p);
+ return true;
+ }
+
+ bool WriteString(const Ch* str, SizeType length) {
+ static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+ 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
+ Z16, Z16, // 30~4F
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
+#undef Z16
+ };
+
+ os_->Put('\"');
+ GenericStringStream<SourceEncoding> is(str);
+ while (is.Tell() < length) {
+ const Ch c = is.Peek();
+ if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
+ // Unicode escaping
+ unsigned codepoint;
+ if (!SourceEncoding::Decode(is, &codepoint))
+ return false;
+ os_->Put('\\');
+ os_->Put('u');
+ if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
+ os_->Put(hexDigits[(codepoint >> 12) & 15]);
+ os_->Put(hexDigits[(codepoint >> 8) & 15]);
+ os_->Put(hexDigits[(codepoint >> 4) & 15]);
+ os_->Put(hexDigits[(codepoint ) & 15]);
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
+ // Surrogate pair
+ unsigned s = codepoint - 0x010000;
+ unsigned lead = (s >> 10) + 0xD800;
+ unsigned trail = (s & 0x3FF) + 0xDC00;
+ os_->Put(hexDigits[(lead >> 12) & 15]);
+ os_->Put(hexDigits[(lead >> 8) & 15]);
+ os_->Put(hexDigits[(lead >> 4) & 15]);
+ os_->Put(hexDigits[(lead ) & 15]);
+ os_->Put('\\');
+ os_->Put('u');
+ os_->Put(hexDigits[(trail >> 12) & 15]);
+ os_->Put(hexDigits[(trail >> 8) & 15]);
+ os_->Put(hexDigits[(trail >> 4) & 15]);
+ os_->Put(hexDigits[(trail ) & 15]);
+ }
+ }
+ else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
+ is.Take();
+ os_->Put('\\');
+ os_->Put(escape[(unsigned char)c]);
+ if (escape[(unsigned char)c] == 'u') {
+ os_->Put('0');
+ os_->Put('0');
+ os_->Put(hexDigits[(unsigned char)c >> 4]);
+ os_->Put(hexDigits[(unsigned char)c & 0xF]);
+ }
+ }
+ else
+ if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
+ return false;
+ }
+ os_->Put('\"');
+ return true;
+ }
+
+ bool WriteStartObject() { os_->Put('{'); return true; }
+ bool WriteEndObject() { os_->Put('}'); return true; }
+ bool WriteStartArray() { os_->Put('['); return true; }
+ bool WriteEndArray() { os_->Put(']'); return true; }
+
+ void Prefix(Type type) {
+ (void)type;
+ if (level_stack_.GetSize() != 0) { // this value is not at root
+ Level* level = level_stack_.template Top<Level>();
+ if (level->valueCount > 0) {
+ if (level->inArray)
+ os_->Put(','); // add comma if it is not the first element in array
+ else // in object
+ os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else {
+ RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
+ hasRoot_ = true;
+ }
+ }
+
+ OutputStream* os_;
+ internal::Stack<StackAllocator> level_stack_;
+ bool hasRoot_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ Writer(const Writer&);
+ Writer& operator=(const Writer&);
+};
+
+// Full specialization for StringStream to prevent memory copying
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt(int i) {
+ char *buffer = os_->Push(11);
+ const char* end = internal::i32toa(i, buffer);
+ os_->Pop(11 - (end - buffer));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
+ char *buffer = os_->Push(10);
+ const char* end = internal::u32toa(u, buffer);
+ os_->Pop(10 - (end - buffer));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
+ char *buffer = os_->Push(21);
+ const char* end = internal::i64toa(i64, buffer);
+ os_->Pop(21 - (end - buffer));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
+ char *buffer = os_->Push(20);
+ const char* end = internal::u64toa(u, buffer);
+ os_->Pop(20 - (end - buffer));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteDouble(double d) {
+ char *buffer = os_->Push(25);
+ char* end = internal::dtoa(d, buffer);
+ os_->Pop(25 - (end - buffer));
+ return true;
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/dep/readline/CMakeLists.txt b/dep/readline/CMakeLists.txt
new file mode 100644
index 00000000000..0e8679ba718
--- /dev/null
+++ b/dep/readline/CMakeLists.txt
@@ -0,0 +1,38 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+if( UNIX )
+ # find Readline (terminal input library) includes and library
+ #
+ # READLINE_INCLUDE_DIR - where the directory containing the READLINE headers can be found
+ # READLINE_LIBRARY - full path to the READLINE library
+ find_path(READLINE_INCLUDE_DIR readline/readline.h)
+ find_library(READLINE_LIBRARY NAMES readline)
+
+ message(STATUS "Found Readline library: ${READLINE_LIBRARY}")
+ message(STATUS "Include dir is: ${READLINE_INCLUDE_DIR}")
+
+ if (NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARY)
+ message(FATAL_ERROR "** Readline library not found!\n** Your distro may provide a binary for Readline e.g. for ubuntu try apt-get install libreadline5-dev")
+ endif ()
+
+ add_library(readline SHARED IMPORTED GLOBAL)
+
+ set_target_properties(readline
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${READLINE_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${READLINE_INCLUDE_DIR}")
+
+else()
+ # Provide a dummy target
+ add_library(readline INTERFACE)
+endif()
diff --git a/dep/recastnavigation/Detour/CMakeLists.txt b/dep/recastnavigation/Detour/CMakeLists.txt
index b21e4ca6273..12be71d32b4 100644
--- a/dep/recastnavigation/Detour/CMakeLists.txt
+++ b/dep/recastnavigation/Detour/CMakeLists.txt
@@ -16,14 +16,18 @@ set(Detour_STAT_SRCS
Source/DetourNavMeshQuery.cpp
Source/DetourNode.cpp
)
-include_directories(Include)
-
-if(WIN32)
- include_directories(
- ${CMAKE_SOURCE_DIR}/dep/zlib
- )
-endif()
add_library(Detour STATIC ${Detour_STAT_SRCS})
-target_link_libraries(Detour ${ZLIB_LIBRARIES})
+target_include_directories(Detour
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/Include)
+
+target_link_libraries(Detour
+ PUBLIC
+ zlib)
+
+set_target_properties(Detour
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/recastnavigation/Recast/CMakeLists.txt b/dep/recastnavigation/Recast/CMakeLists.txt
index 738c010eb05..1eac4e75399 100644
--- a/dep/recastnavigation/Recast/CMakeLists.txt
+++ b/dep/recastnavigation/Recast/CMakeLists.txt
@@ -14,21 +14,24 @@ set(Recast_STAT_SRCS
Source/RecastArea.cpp
Source/RecastContour.cpp
Source/RecastFilter.cpp
- Source/RecastLayers.cpp
+ Source/RecastLayers.cpp
Source/RecastMesh.cpp
Source/RecastMeshDetail.cpp
Source/RecastRasterization.cpp
Source/RecastRegion.cpp
)
-include_directories(Include)
+add_library(Recast STATIC ${Recast_STAT_SRCS})
-if(WIN32)
- include_directories(
- ${CMAKE_SOURCE_DIR}/dep/zlib
- )
-endif()
+target_include_directories(Recast
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/Include)
-add_library(Recast STATIC ${Recast_STAT_SRCS})
+target_link_libraries(Recast
+ PUBLIC
+ zlib)
-target_link_libraries(Recast ${ZLIB_LIBRARIES}) \ No newline at end of file
+set_target_properties(Recast
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/threads/CMakeLists.txt b/dep/threads/CMakeLists.txt
new file mode 100644
index 00000000000..48e5eb00723
--- /dev/null
+++ b/dep/threads/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+find_package(Threads REQUIRED)
+
+add_library(threads INTERFACE)
+target_link_libraries(threads
+ INTERFACE
+ ${CMAKE_THREAD_LIBS_INIT})
diff --git a/dep/utf8cpp/CMakeLists.txt b/dep/utf8cpp/CMakeLists.txt
new file mode 100644
index 00000000000..edf8604d44c
--- /dev/null
+++ b/dep/utf8cpp/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+add_library(utf8cpp INTERFACE)
+
+target_include_directories(utf8cpp
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/dep/valgrind/CMakeLists.txt b/dep/valgrind/CMakeLists.txt
new file mode 100644
index 00000000000..d67cd33b426
--- /dev/null
+++ b/dep/valgrind/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+add_library(valgrind INTERFACE)
+
+target_include_directories(valgrind
+ INTERFACE
+ "${VALGRIND_INCLUDE_DIR}")
diff --git a/dep/zlib/CMakeLists.txt b/dep/zlib/CMakeLists.txt
index 7feb134bcd5..b3e3d58fe55 100644
--- a/dep/zlib/CMakeLists.txt
+++ b/dep/zlib/CMakeLists.txt
@@ -8,22 +8,43 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-SET(zlib_STAT_SRCS
- adler32.c
- compress.c
- crc32.c
- deflate.c
- infback.c
- inffast.c
- inflate.c
- inftrees.c
- trees.c
- uncompr.c
- zutil.c
-)
+if(UNIX)
+ # Look for an installed zlib on unix
+ find_package(ZLIB REQUIRED)
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
-)
+ add_library(zlib SHARED IMPORTED GLOBAL)
-add_library(zlib STATIC ${zlib_STAT_SRCS})
+ set_target_properties(zlib
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${ZLIB_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${ZLIB_INCLUDE_DIRS}")
+else()
+ # Use the bundled source on windows
+ SET(zlib_STAT_SRCS
+ adler32.c
+ compress.c
+ crc32.c
+ deflate.c
+ infback.c
+ inffast.c
+ inflate.c
+ inftrees.c
+ trees.c
+ uncompr.c
+ zutil.c
+ )
+
+ add_library(zlib STATIC
+ ${zlib_STAT_SRCS})
+
+ target_include_directories(zlib
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+ set_target_properties(zlib
+ PROPERTIES
+ FOLDER
+ "dep")
+endif()
diff --git a/dep/zmqpp/zmqpp/compatibility.hpp b/dep/zmqpp/zmqpp/compatibility.hpp
deleted file mode 100644
index 103b2c82ebd..00000000000
--- a/dep/zmqpp/zmqpp/compatibility.hpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * \file
- *
- * \date 10 Sep 2011
- * \author ron
- * \author Ben Gray (\@benjamg)
- *
- * A fair number of C++0x (or more accurately C++11) features are used in this
- * library and as this project is used where I work on older compilers this
- * file was created to help.
- *
- * C++ features and their workaround where not supported:
- * \li lambda functions - disabled, these are only used in the test anyway.
- * \li typesafe enums - replaced with enum where comparisons needed.
- * \li nullptr - defined to null.
- *
- * As of the port to version 3.1 (libzmqpp version 1.1.0) this file will also
- * be used to maintain compatablity with multiple versions of 0mq
- */
-
-#ifndef ZMQPP_COMPATIBILITY_HPP_
-#define ZMQPP_COMPATIBILITY_HPP_
-
-#include <zmq.h>
-#include <cstdint>
-
-// Currently we require at least 0mq version 2.2.x
-#define ZMQPP_REQUIRED_ZMQ_MAJOR 2
-#define ZMQPP_REQUIRED_ZMQ_MINOR 2
-
-#if (ZMQ_VERSION_MAJOR < ZMQPP_REQUIRED_ZMQ_MAJOR) || ((ZMQ_VERSION_MAJOR == ZMQPP_REQUIRED_ZMQ_MAJOR) && (ZMQ_VERSION_MINOR < ZMQPP_REQUIRED_ZMQ_MINOR))
-#error zmqpp requires a later version of 0mq
-#endif
-
-// Experimental feature support
-#if (ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR == 0)
-#define ZMQ_EXPERIMENTAL_LABELS
-#endif
-
-// Deal with older versions of gcc
-#if defined(__GNUC__) && !defined(__clang__)
-#if __GNUC__ == 4
-
-// Deal with older gcc not supporting C++0x typesafe enum class name {} comparison
-#if __GNUC_MINOR__ < 4
-#define ZMQPP_COMPARABLE_ENUM enum
-#endif
-
-#if __GNUC_MINOR__ == 4
-#if __GNUC_PATCHLEVEL__ < 1
-#undef ZMQPP_COMPARABLE_ENUM
-#define ZMQPP_COMPARABLE_ENUM enum
-#endif // if __GNUC_PATCHLEVEL__ < 1
-#endif // if __GNUC_MINOR__ == 4
-
-// Deal with older gcc not supporting C++0x lambda function
-#if __GNUC_MINOR__ < 5
-#define ZMQPP_IGNORE_LAMBDA_FUNCTION_TESTS
-#define ZMQPP_EXPLICITLY_DELETED
-#endif // if __GNUC_MINOR__ < 5
-
-// Deal with older gcc not supporting C++0x nullptr
-#if __GNUC_MINOR__ < 6
-#define nullptr NULL
-#define NOEXCEPT
-#endif // if __GNUC_MINOR__ < 6
-
-#endif // if __GNUC_ == 4
-#endif // if defined(__GNUC__) && !defined(__clang__)
-
-#if defined(_MSC_VER)
-#define NOEXCEPT throw()
-#if _MSC_VER < 1800
-#define ZMQPP_EXPLICITLY_DELETED
-#endif // if _MSC_VER < 1800
-#if _MSC_VER < 1600
-#define nullptr NULL
-#define ZMQPP_IGNORE_LAMBDA_FUNCTION_TESTS
-#define ZMQPP_COMPARABLE_ENUM enum
-#endif // if _MSC_VER < 1600
-#endif // if defined(_MSC_VER)
-
-// Generic state, assume a modern compiler
-#ifndef ZMQPP_COMPARABLE_ENUM
-#define ZMQPP_COMPARABLE_ENUM enum class
-#endif
-
-#ifndef ZMQPP_EXPLICITLY_DELETED
-#define ZMQPP_EXPLICITLY_DELETED = delete
-#endif
-
-#ifndef NOEXCEPT
-#define NOEXCEPT noexcept
-#endif
-
-#endif /* ZMQPP_COMPATIBILITY_HPP_ */
-
diff --git a/dep/zmqpp/zmqpp/context.cpp b/dep/zmqpp/zmqpp/context.cpp
deleted file mode 100644
index 32c657199dc..00000000000
--- a/dep/zmqpp/zmqpp/context.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * \file
- *
- * \date 9 Aug 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#include "context.hpp"
-
-namespace zmqpp
-{
-
-void context::terminate()
-{
- int result;
- do
- {
-#if (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2))
- result = zmq_term(_context);
-#else
- result = zmq_ctx_destroy(_context);
-#endif
- } while (result != 0 && zmq_errno() == EINTR);
- if (result != 0) { throw zmq_internal_exception(); }
- _context = nullptr;
-}
-
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
-void context::set(context_option const option, int const value)
-{
- if (nullptr == _context) { throw invalid_instance("context is invalid"); }
-
- if (0 != zmq_ctx_set(_context, static_cast<int>(option), value))
- {
- throw zmq_internal_exception();
- }
-}
-
-int context::get(context_option const option)
-{
- if (nullptr == _context) { throw invalid_instance("context is invalid"); }
-
- int result = zmq_ctx_get(_context, static_cast<int>(option));
-
- if (result < 0)
- {
- throw zmq_internal_exception();
- }
-
- return result;
-}
-#endif
-
-}
diff --git a/dep/zmqpp/zmqpp/context.hpp b/dep/zmqpp/zmqpp/context.hpp
deleted file mode 100644
index 3ffaf791440..00000000000
--- a/dep/zmqpp/zmqpp/context.hpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/**
- * \file
- *
- * \date 9 Aug 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_CONTEXT_HPP_
-#define ZMQPP_CONTEXT_HPP_
-
-#include <cassert>
-
-#include <zmq.h>
-
-#include "compatibility.hpp"
-#include "exception.hpp"
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
-#include "context_options.hpp"
-#endif
-
-namespace zmqpp
-{
-
-/*!
- * The context class represents internal zmq context and io threads.
- *
- * By default the context class will create one thread, however this can be
- * overridden in the constructor.
- *
- * The context class is the only object that can be considered thread safe.
- *
- * All sockets using endpoints other than inproc require the context to have
- * at least one thread.
- *
- * This class is c++0x move supporting and cannot be copied.
- */
-class context
-{
-public:
-
-#if (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2))
- /*!
- * Initialise the 0mq context.
- *
- * If only inproc is used then the context may be created with zero threads.
- * Any inproc endpoint using sockets must be created using the same context.
- *
- * The context is thread safe an may be used anywhere in your application,
- * however there is no requirement (other than inproc restrictions) for you
- * to do this.
- *
- * \param threads an integer argument for the number of required threads. Defaults to 1.
- */
- context(int const& threads = 1)
-#else
- /*!
- * Initialise the 0mq context.
- *
- * The context is thread safe an may be used anywhere in your application,
- * however there is no requirement (other than inproc restrictions) for you
- * to do this.
- */
- context()
-#endif
- : _context(nullptr)
- {
-#if (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2))
- _context = zmq_init(threads);
-#else
- _context = zmq_ctx_new();
-#endif
-
- if (nullptr == _context)
- {
- throw zmq_internal_exception();
- }
- }
-
- /*!
- * Closes the 0mq context.
- *
- * Any blocking calls other than a socket close will return with an error.
- *
- * If there are open sockets will block while zmq internal buffers are
- * processed up to a limit specified by that sockets linger option.
- */
- ~context() NOEXCEPT
- {
- if (nullptr != _context)
- {
- terminate();
- }
- }
-
- /*!
- * Move supporting constructor.
- *
- * Allows zero-copy move semantics to be used with this class.
- *
- * \param source a rvalue instance of the object who's internals we wish to steal.
- */
- context(context&& source) NOEXCEPT
- : _context(source._context)
- {
- source._context = nullptr;
- }
-
- /*!
- * Move supporting operator.
- *
- * Allows zero-copy move semantics to be used with this class.
- *
- * \param source an rvalue instance of the context who's internals we wish to steal.
- */
- context& operator=(context&& source) NOEXCEPT
- {
- std::swap( _context, source._context );
- return *this;
- }
-
- /*!
- * Terminate the current context.
- *
- * Any blocking calls other than a socket close will return with an error.
- *
- * If there are open sockets will block while zmq internal buffers are
- * processed up to a limit specified by that sockets linger option.
- */
- void terminate();
-
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
- /*!
- * Set the value of an option in the underlaying zmq context.
- *
- * \param option a valid ::context_option
- * \param value to set the option to
- */
- void set(context_option const option, int const value);
-
- /*!
- * Get a context option from the underlaying zmq context.
- *
- * \param option a valid ::context_option
- * \return context option value
- */
- int get(context_option const option);
-#endif
-
- /*!
- * Validity checking of the context
- *
- * Checks if the underlying 0mq context for this instance is valid.
- *
- * Contexts should always be valid unless people are doing 'fun' things with
- * std::move.
- *
- * \return boolean true if the object is valid.
- */
- operator bool() const NOEXCEPT
- {
- return nullptr != _context;
- }
-
- /*!
- * Access to the raw 0mq context
- *
- * \return void pointer to the underlying 0mq context.
- */
- operator void*() const NOEXCEPT
- {
- return _context;
- }
-
-private:
- void* _context;
-
- // No copy - private and not implemented
- context(context const&) ZMQPP_EXPLICITLY_DELETED;
- context& operator=(context const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED;
-};
-
-}
-
-#endif /* ZMQPP_CONTEXT_HPP_ */
diff --git a/dep/zmqpp/zmqpp/context_options.hpp b/dep/zmqpp/zmqpp/context_options.hpp
deleted file mode 100644
index b2e2cf4805f..00000000000
--- a/dep/zmqpp/zmqpp/context_options.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * \file
- *
- * \date 3 Jul 2013
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_CONTEXT_OPTIONS_HPP_
-#define ZMQPP_CONTEXT_OPTIONS_HPP_
-
-namespace zmqpp
-{
-
-/** \todo Expand the information on the options to make it actually useful. */
-/*!
- * \brief possible Context options in zmq
- */
-
-enum class context_option {
- io_threads = ZMQ_IO_THREADS, /*!< I/O thread count */
- max_sockets = ZMQ_MAX_SOCKETS, /*!< Maximum supported sockets */
-};
-
-}
-
-#endif /* ZMQPP_CONTEXT_OPTIONS_HPP_ */
diff --git a/dep/zmqpp/zmqpp/exception.hpp b/dep/zmqpp/zmqpp/exception.hpp
deleted file mode 100644
index a0b234769ce..00000000000
--- a/dep/zmqpp/zmqpp/exception.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * \file
- *
- * \date 9 Aug 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_EXCEPTION_HPP_
-#define ZMQPP_EXCEPTION_HPP_
-
-#include <stdexcept>
-#include <string>
-
-#include <zmq.h>
-
-namespace zmqpp
-{
-
-/** \todo Have a larger variety of exceptions with better state debug information */
-
-/*!
- * Represents the base zmqpp exception.
- *
- * All zmqpp runtime exceptions are children of this class.
- * The class itself does not provide any special access fields but it only
- * for convince when catching exceptions.
- *
- * The class extends std::runtime_error.
- *
- */
-class exception : public std::runtime_error
-{
-public:
- /*!
- * Standard exception constructor.
- *
- * \param message a string representing the error message.
- */
- exception(std::string const& message)
- : std::runtime_error(message)
- { }
-};
-
-/*!
- * Represents an attempt to use an invalid object.
- *
- * Objects may be invalid initially or after a shutdown or close.
- */
-class invalid_instance : public exception
-{
-public:
- invalid_instance(std::string const& message)
- : exception(message)
- { }
-};
-
-/*!
- * Represents internal zmq errors.
- *
- * Any error response from the zmq bindings will be wrapped in this error.
- *
- * The class provides access to the zmq error number via zmq_error().
- */
-class zmq_internal_exception : public exception
-{
-public:
- /*!
- * Uses the zmq functions to pull out error messages and numbers.
- */
- zmq_internal_exception()
- : exception(zmq_strerror(zmq_errno()))
- , _error(zmq_errno())
- { }
-
- /*!
- * Retrieve the zmq error number associated with this exception.
- * \return zmq error number
- */
- int zmq_error() const { return _error; }
-
-private:
- int _error;
-};
-
-}
-
-#endif /* ZMQPP_EXCEPTION_HPP_ */
diff --git a/dep/zmqpp/zmqpp/frame.cpp b/dep/zmqpp/zmqpp/frame.cpp
deleted file mode 100644
index 4c512ae1010..00000000000
--- a/dep/zmqpp/zmqpp/frame.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * \file
- *
- * \date 8 Jan 2014
- * \author Ben Gray (\@benjamg)
- */
-
-#include <cassert>
-#include <cstring>
-
-#include "exception.hpp"
-#include "frame.hpp"
-
-namespace zmqpp {
-
-frame::frame()
- : _sent( false )
-{
- if( 0 != zmq_msg_init( &_msg ) )
- {
- throw zmq_internal_exception();
- }
-}
-
-frame::frame(size_t const size)
- : _sent( false )
-{
- if( 0 != zmq_msg_init_size( &_msg, size ) )
- {
- throw zmq_internal_exception();
- }
-}
-
-frame::frame(void const* part, size_t const size)
- : _sent( false )
-{
- if( 0 != zmq_msg_init_size( &_msg, size ) )
- {
- throw zmq_internal_exception();
- }
-
- void* msg_data = zmq_msg_data( &_msg );
- memcpy( msg_data, part, size );
-}
-
-frame::frame(void* part, size_t const size, zmq_free_fn *ffn, void *hint)
- : _sent( false )
-{
- if( 0 != zmq_msg_init_data( &_msg, part, size, ffn, hint ) )
- {
- throw zmq_internal_exception();
- }
-}
-
-frame::~frame()
-{
-#ifndef NDEBUG // unused assert variable in release
- int result = zmq_msg_close( &_msg );
- assert(0 == result);
-#else
- zmq_msg_close( &_msg );
-#endif // NDEBUG
-}
-
-frame::frame(frame&& other)
- : _sent( other._sent )
-{
- zmq_msg_init( &_msg );
- zmq_msg_move( &_msg, &other._msg );
- other._sent = false;
-}
-
-frame& frame::operator=(frame&& other)
-{
- zmq_msg_init( &_msg );
- zmq_msg_move( &_msg, &other._msg );
- std::swap( _sent, other._sent );
-
- return *this;
-}
-
-frame frame::copy() const
-{
- frame other( size() );
- other._sent = _sent;
-
- if( 0 != zmq_msg_copy( &other._msg, const_cast<zmq_msg_t*>(&_msg) ) )
- {
- throw zmq_internal_exception();
- }
-
- return other;
-}
-
-} // namespace zmqpp
diff --git a/dep/zmqpp/zmqpp/frame.hpp b/dep/zmqpp/zmqpp/frame.hpp
deleted file mode 100644
index c9e4b9b7d82..00000000000
--- a/dep/zmqpp/zmqpp/frame.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * \file
- *
- * \date 8 Jan 2014
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_MESSAGE_FRAME_HPP_
-#define ZMQPP_MESSAGE_FRAME_HPP_
-
-#include <zmq.h>
-
-#include "compatibility.hpp"
-
-namespace zmqpp {
-
-/*!
- * \brief an internal frame wrapper for a single zmq message
- *
- * This frame wrapper consists of a zmq message and meta data it is used
- * by the zmqpp message class to keep track of parts in the internal
- * queue. It is unlikely you need to use this class.
- */
-class frame
-{
-public:
- frame();
- frame(size_t const size);
- frame(void const* part, size_t const size);
- frame(void* part, size_t const size, zmq_free_fn *ffn, void *hint);
-
- ~frame();
-
- bool is_sent() const { return _sent; }
- void const* data() const { return zmq_msg_data( const_cast<zmq_msg_t*>(&_msg) ); }
- size_t size() const { return zmq_msg_size( const_cast<zmq_msg_t*>(&_msg) ); }
-
- void mark_sent() { _sent = true; }
- zmq_msg_t& msg() { return _msg; }
-
- // Move operators
- frame(frame&& other);
- frame& operator=(frame&& other);
-
- frame copy() const;
-
-private:
- bool _sent;
- zmq_msg_t _msg;
-
- // Disable implicit copy support, code must request a copy to clone
- frame(frame const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED;
- frame& operator=(frame const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED;
-};
-
-} // namespace zmqpp
-
-#endif /* ZMQPP_MESSAGE_FRAME_HPP_ */
diff --git a/dep/zmqpp/zmqpp/inet.hpp b/dep/zmqpp/zmqpp/inet.hpp
deleted file mode 100644
index e0c3b146e37..00000000000
--- a/dep/zmqpp/zmqpp/inet.hpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
- * \file
- *
- * \date 10 Aug 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_INET_HPP_
-#define ZMQPP_INET_HPP_
-
-/** \todo cross-platform version of including headers. */
-// We get htons and htonl from here
-#ifdef _WIN32
-#include <WinSock2.h>
-#else
-#include <netinet/in.h>
-#endif
-
-#include "compatibility.hpp"
-
-namespace zmqpp
-{
-
-/*!
- * \brief Possible byte order types.
- *
- * An enumeration of all the known order types, all two of them.
- * There is also an entry for unknown which is just used as a default.
- */
-ZMQPP_COMPARABLE_ENUM order {
- big_endian, /*!< byte order is big endian */
- little_endian /*!< byte order is little endian */
-};
-
-/*!
- * Common code for the 64bit versions of htons/htons and ntohs/ntohl
- *
- * As htons and ntohs (or htonl and ntohs) always just do the same thing, ie
- * swap bytes if the host order differs from network order or otherwise don't
- * do anything, it seemed silly to type the code twice.
- *
- * \note This code assumes network order is always big endian. Which it is.
- * \note The host endian is only checked once and afterwards assumed to remain
- * the same.
- *
- * \param value_to_check unsigned 64 bit integer to swap
- * \return swapped (or not) unsigned 64 bit integer
- */
-inline uint64_t swap_if_needed(uint64_t const value_to_check)
-{
- static order host_order = (htonl(42) == 42) ? order::big_endian : order::little_endian;
-
- if (order::big_endian == host_order)
- {
- return value_to_check;
- }
-
- union {
- uint64_t integer;
- uint8_t bytes[8];
- } value { value_to_check };
-
- std::swap(value.bytes[0], value.bytes[7]);
- std::swap(value.bytes[1], value.bytes[6]);
- std::swap(value.bytes[2], value.bytes[5]);
- std::swap(value.bytes[3], value.bytes[4]);
-
- return value.integer;
-}
-
-/*!
- * 64 bit version of the htons/htonl
- *
- * I've used the name htonll to try and keep with the htonl naming scheme.
- *
- * \param hostlonglong unsigned 64 bit host order integer
- * \return unsigned 64 bit network order integer
- */
-#ifndef htonll
-inline uint64_t htonll(uint64_t const hostlonglong)
-{
- return zmqpp::swap_if_needed(hostlonglong);
-}
-#endif
-
-/*!
- * 64 bit version of the ntohs/ntohl
- *
- * I've used the name htonll to try and keep with the htonl naming scheme.
- *
- * \param networklonglong unsigned 64 bit network order integer
- * \return unsigned 64 bit host order integer
- */
-#ifndef ntohll
-inline uint64_t ntohll(uint64_t const networklonglong)
-{
- return zmqpp::swap_if_needed(networklonglong);
-}
-#endif
-
-/*!
- * floating point version of the htons/htonl
- *
- * \param value host order floating point
- * \returns network order floating point
- */
-inline float htonf(float value)
-{
- assert(sizeof(float) == sizeof(uint32_t));
-
- uint32_t temp;
- memcpy(&temp, &value, sizeof(uint32_t));
- temp = htonl( temp );
- memcpy(&value, &temp, sizeof(uint32_t));
-
- return value;
-}
-
-/*!
- * floating point version of the ntohs/ntohl
- *
- * \param value network order float
- * \returns host order float
- */
-inline float ntohf(float value)
-{
- assert(sizeof(float) == sizeof(uint32_t));
-
- uint32_t temp;
- memcpy(&temp, &value, sizeof(uint32_t));
- temp = ntohl( temp );
- memcpy(&value, &temp, sizeof(uint32_t));
-
- return value;
-}
-
-/*!
- * double precision floating point version of the htons/htonl
- *
- * \param value host order double precision floating point
- * \returns network order double precision floating point
- */
-inline double htond(double value)
-{
- assert(sizeof(double) == sizeof(uint64_t));
-
- uint64_t temp;
- memcpy(&temp, &value, sizeof(uint64_t));
- temp = htonll(temp);
- memcpy(&value, &temp, sizeof(uint64_t));
-
- return value;
-}
-
-/*!
- * double precision floating point version of the ntohs/ntohl
- *
- * \param value network order double precision floating point
- * \returns host order double precision floating point
- */
-inline double ntohd(double value)
-{
- assert(sizeof(double) == sizeof(uint64_t));
-
- uint64_t temp;
- memcpy(&temp, &value, sizeof(uint64_t));
- temp = ntohll(temp);
- memcpy(&value, &temp, sizeof(uint64_t));
-
- return value;
-}
-
-}
-
-#endif /* INET_HPP_ */
diff --git a/dep/zmqpp/zmqpp/message.cpp b/dep/zmqpp/zmqpp/message.cpp
deleted file mode 100644
index 4d81d247c62..00000000000
--- a/dep/zmqpp/zmqpp/message.cpp
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Created on: 9 Aug 2011
- * Author: Ben Gray (@benjamg)
- */
-
-#include <cassert>
-#include <cstring>
-
-#include "exception.hpp"
-#include "inet.hpp"
-#include "message.hpp"
-
-namespace zmqpp
-{
-
-/*!
- * \brief internal construct
- * \internal handles bubbling callback from zmq c style to the c++ functor provided
- */
-struct callback_releaser
-{
- message::release_function func;
-};
-
-message::message()
- : _parts()
- , _read_cursor(0)
-{
-}
-
-message::~message()
-{
- _parts.clear();
-}
-
-size_t message::parts() const
-{
- return _parts.size();
-}
-
-/*
- * The two const_casts in size and raw_data are a little bit hacky
- * but neither of these methods called this way actually modify data
- * so accurately represent the intent of these calls.
- */
-
-size_t message::size(size_t const part /* = 0 */) const
-{
- if(part >= _parts.size())
- {
- throw exception("attempting to request a message part outside the valid range");
- }
-
- return _parts[part].size();
-}
-
-void const* message::raw_data(size_t const part /* = 0 */) const
-{
- if(part >= _parts.size())
- {
- throw exception("attempting to request a message part outside the valid range");
- }
-
- return _parts[part].data();
-}
-
-zmq_msg_t& message::raw_msg(size_t const part /* = 0 */)
-{
- if(part >= _parts.size())
- {
- throw exception("attempting to request a message part outside the valid range");
- }
-
- return _parts[part].msg();
-}
-
-zmq_msg_t& message::raw_new_msg()
-{
- _parts.push_back( frame() );
-
- return _parts.back().msg();
-}
-
-zmq_msg_t& message::raw_new_msg(size_t const reserve_data_size)
-{
- _parts.push_back( frame(reserve_data_size) );
-
- return _parts.back().msg();
-}
-
-std::string message::get(size_t const part /* = 0 */) const
-{
- return std::string(static_cast<char const*>(raw_data(part)), size(part));
-}
-
-
-// Move operators will take ownership of message parts without copying
-void message::move(void* part, size_t const size, release_function const& release)
-{
- callback_releaser* hint = new callback_releaser();
- hint->func = release;
-
- _parts.push_back( frame( part, size, &message::release_callback, hint ) );
-}
-
-// Stream reader style
-void message::reset_read_cursor()
-{
- _read_cursor = 0;
-}
-
-void message::get(int8_t& integer, size_t const part) const
-{
- assert(sizeof(int8_t) == size(part));
-
- int8_t const* byte = static_cast<int8_t const*>(raw_data(part));
- integer = *byte;
-}
-
-void message::get(int16_t& integer, size_t const part) const
-{
- assert(sizeof(int16_t) == size(part));
-
- uint16_t const* network_order = static_cast<uint16_t const*>(raw_data(part));
- integer = static_cast<int16_t>(ntohs(*network_order));
-}
-
-void message::get(int32_t& integer, size_t const part) const
-{
- assert(sizeof(int32_t) == size(part));
-
- uint32_t const* network_order = static_cast<uint32_t const*>(raw_data(part));
- integer = static_cast<int32_t>(htonl(*network_order));
-}
-
-void message::get(int64_t& integer, size_t const part) const
-{
- assert(sizeof(int64_t) == size(part));
-
- uint64_t const* network_order = static_cast<uint64_t const*>(raw_data(part));
- integer = static_cast<int64_t>(htonll(*network_order));
-}
-
-void message::get(uint8_t& unsigned_integer, size_t const part) const
-{
- assert(sizeof(uint8_t) == size(part));
-
- uint8_t const* byte = static_cast<uint8_t const*>(raw_data(part));
- unsigned_integer = *byte;
-}
-
-void message::get(uint16_t& unsigned_integer, size_t const part) const
-{
- assert(sizeof(uint16_t) == size(part));
-
- uint16_t const* network_order = static_cast<uint16_t const*>(raw_data(part));
- unsigned_integer = ntohs(*network_order);
-}
-
-void message::get(uint32_t& unsigned_integer, size_t const part) const
-{
- assert(sizeof(uint32_t) == size(part));
-
- uint32_t const* network_order = static_cast<uint32_t const*>(raw_data(part));
- unsigned_integer = ntohl(*network_order);
-}
-
-void message::get(uint64_t& unsigned_integer, size_t const part) const
-{
- assert(sizeof(uint64_t) == size(part));
-
- uint64_t const* network_order = static_cast<uint64_t const*>(raw_data(part));
- unsigned_integer = ntohll(*network_order);
-}
-
-void message::get(float& floating_point, size_t const part) const
-{
- assert(sizeof(float) == size(part));
-
- float const* network_order = static_cast<float const*>(raw_data(part));
- floating_point = zmqpp::ntohf(*network_order);
-}
-
-void message::get(double& double_precision, size_t const part) const
-{
- assert(sizeof(double) == size(part));
-
- double const* network_order = static_cast<double const*>(raw_data(part));
- double_precision = zmqpp::ntohd(*network_order);
-}
-
-void message::get(bool& boolean, size_t const part) const
-{
- assert(sizeof(uint8_t) == size(part));
-
- uint8_t const* byte = static_cast<uint8_t const*>(raw_data(part));
- boolean = (*byte != 0);
-}
-
-void message::get(std::string& string, size_t const part) const
-{
- string.assign( get(part) );
-}
-
-
-// Stream writer style - these all use copy styles
-message& message::operator<<(int8_t const integer)
-{
- add(reinterpret_cast<void const*>(&integer), sizeof(int8_t));
- return *this;
-}
-
-message& message::operator<<(int16_t const integer)
-{
- uint16_t network_order = htons(static_cast<uint16_t>(integer));
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint16_t));
-
- return *this;
-}
-
-message& message::operator<<(int32_t const integer)
-{
- uint32_t network_order = htonl(static_cast<uint32_t>(integer));
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint32_t));
-
- return *this;
-}
-
-message& message::operator<<(int64_t const integer)
-{
- uint64_t network_order = htonll(static_cast<uint64_t>(integer));
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint64_t));
-
- return *this;
-}
-
-
-message& message::operator<<(uint8_t const unsigned_integer)
-{
- add(reinterpret_cast<void const*>(&unsigned_integer), sizeof(uint8_t));
- return *this;
-}
-
-message& message::operator<<(uint16_t const unsigned_integer)
-{
- uint16_t network_order = htons(unsigned_integer);
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint16_t));
-
- return *this;
-}
-
-message& message::operator<<(uint32_t const unsigned_integer)
-{
- uint32_t network_order = htonl(unsigned_integer);
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint32_t));
-
- return *this;
-}
-
-message& message::operator<<(uint64_t const unsigned_integer)
-{
- uint64_t network_order = htonll(unsigned_integer);
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint64_t));
-
- return *this;
-}
-
-message& message::operator<<(float const floating_point)
-{
- assert(sizeof(float) == 4);
-
- float network_order = zmqpp::htonf(floating_point);
- add(&network_order, sizeof(float));
-
- return *this;
-}
-
-message& message::operator<<(double const double_precision)
-{
- assert(sizeof(double) == 8);
-
- double network_order = zmqpp::htond(double_precision);
- add(&network_order, sizeof(double));
-
- return *this;
-}
-
-message& message::operator<<(bool const boolean)
-{
- uint8_t byte = (boolean) ? 1 : 0;
- add(reinterpret_cast<void const*>(&byte), sizeof(uint8_t));
-
- return *this;
-}
-
-message& message::operator<<(char const* c_string)
-{
- add(reinterpret_cast<void const*>(c_string), strlen(c_string));
- return *this;
-}
-
-message& message::operator<<(std::string const& string)
-{
- add(reinterpret_cast<void const*>(string.data()), string.size());
- return *this;
-}
-
-void message::push_front(void const* part, size_t const size)
-{
- _parts.emplace( _parts.begin(), part, size );
-}
-
-void message::push_front(int8_t const integer)
-{
- push_front(&integer, sizeof(int8_t));
-}
-
-void message::push_front(int16_t const integer)
-{
- uint16_t network_order = htons(static_cast<uint16_t>(integer));
- push_front(&network_order, sizeof(uint16_t));
-}
-
-void message::push_front(int32_t const integer)
-{
- uint32_t network_order = htonl(static_cast<uint32_t>(integer));
- push_front(&network_order, sizeof(uint32_t));
-}
-
-void message::push_front(int64_t const integer)
-{
- uint64_t network_order = htonll(static_cast<uint64_t>(integer));
- push_front(&network_order, sizeof(uint64_t));
-}
-
-
-void message::push_front(uint8_t const unsigned_integer)
-{
- push_front(&unsigned_integer, sizeof(uint8_t));
-}
-
-void message::push_front(uint16_t const unsigned_integer)
-{
- uint16_t network_order = htons(unsigned_integer);
- push_front(&network_order, sizeof(uint16_t));
-}
-
-void message::push_front(uint32_t const unsigned_integer)
-{
- uint32_t network_order = htonl(unsigned_integer);
- push_front(&network_order, sizeof(uint32_t));
-}
-
-void message::push_front(uint64_t const unsigned_integer)
-{
- uint64_t network_order = htonll(unsigned_integer);
- push_front(&network_order, sizeof(uint64_t));
-}
-
-void message::push_front(float const floating_point)
-{
- assert(sizeof(float) == 4);
-
- float network_order = zmqpp::htonf(floating_point);
- push_front(&network_order, sizeof(float));
-}
-
-void message::push_front(double const double_precision)
-{
- assert(sizeof(double) == 8);
-
- double network_order = zmqpp::htond(double_precision);
- push_front(&network_order, sizeof(double));
-}
-
-void message::push_front(bool const boolean)
-{
- uint8_t byte = (boolean) ? 1 : 0;
- push_front(&byte, sizeof(uint8_t));
-}
-
-void message::push_front(char const* c_string)
-{
- push_front(c_string, strlen(c_string));
-}
-
-void message::push_front(std::string const& string)
-{
- push_front(string.data(), string.size());
-}
-
-void message::pop_front()
-{
- _parts.erase( _parts.begin() );
-}
-
-void message::pop_back()
-{
- _parts.pop_back();
-}
-
-message::message(message&& source) NOEXCEPT
- : _parts()
- , _read_cursor(0)
-{
- std::swap(_parts, source._parts);
-}
-
-message& message::operator=(message&& source) NOEXCEPT
-{
- std::swap(_parts, source._parts);
- return *this;
-}
-
-message message::copy() const
-{
- message msg;
- msg.copy(*this);
- return msg;
-}
-
-void message::copy(message const& source)
-{
- _parts.resize( source._parts.size() );
- for(size_t i = 0; i < source._parts.size(); ++i)
- {
- _parts[i] = source._parts[i].copy();
- }
-
- // we don't need a copy of the releasers as we did data copies of the internal data,
- //_releasers = source._releasers;
- //_strings = source._strings
-}
-
-// Used for internal tracking
-void message::sent(size_t const part)
-{
- // sanity check
- assert(!_parts[part].is_sent());
- _parts[part].mark_sent();
-}
-
-// Note that these releasers are not thread safe, the only safety is provided by
-// the socket class taking ownership so no updates can happen while zmq does it's thing
-// If used in a custom class this has to be dealt with.
-void message::release_callback(void* data, void* hint)
-{
- callback_releaser* releaser = static_cast<callback_releaser*>(hint);
- releaser->func(data);
-
- delete releaser;
-}
-
-}
diff --git a/dep/zmqpp/zmqpp/message.hpp b/dep/zmqpp/zmqpp/message.hpp
deleted file mode 100644
index 2a747bfd1db..00000000000
--- a/dep/zmqpp/zmqpp/message.hpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/**
- * \file
- *
- * \date 9 Aug 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_MESSAGE_HPP_
-#define ZMQPP_MESSAGE_HPP_
-
-#include <functional>
-#include <string>
-#include <unordered_map>
-#include <vector>
-#include <utility>
-#include <cassert>
-
-#include <zmq.h>
-
-#include "compatibility.hpp"
-#include "frame.hpp"
-
-namespace zmqpp
-{
-
-/*!
- * \brief a zmq message with optional multipart support
- *
- * A zmq message is made up of one or more parts which are sent together to
- * the target endpoints. zmq guarantees either the whole message or none
- * of the message will be delivered.
- */
-class message
-{
-public:
- /*!
- * \brief callback to release user allocated data.
- *
- * The release function will be called on any void* moved part.
- * It must be thread safe to the extent that the callback may occur on
- * one of the context threads.
- *
- * The function called will be passed a single variable which is the
- * pointer to the memory allocated.
- */
- typedef std::function<void (void*)> release_function;
-
- message();
- ~message();
-
- template <typename T, typename ...Args>
- message(T const &part, Args &&...args)
- : message()
- {
- add(part, std::forward<Args>(args)...);
- }
-
- size_t parts() const;
- size_t size(size_t const part) const;
- std::string get(size_t const part) const;
-
- void get(int8_t& integer, size_t const part) const;
- void get(int16_t& integer, size_t const part) const;
- void get(int32_t& integer, size_t const part) const;
- void get(int64_t& integer, size_t const part) const;
-
- void get(uint8_t& unsigned_integer, size_t const part) const;
- void get(uint16_t& unsigned_integer, size_t const part) const;
- void get(uint32_t& unsigned_integer, size_t const part) const;
- void get(uint64_t& unsigned_integer, size_t const part) const;
-
- void get(float& floating_point, size_t const part) const;
- void get(double& double_precision, size_t const part) const;
- void get(bool& boolean, size_t const part) const;
-
- void get(std::string& string, size_t const part) const;
-
- // Warn: If a pointer type is requested the message (well zmq) still 'owns'
- // the data and will release it when the message object is freed.
- template<typename Type>
- Type get(size_t const part)
- {
- Type value;
- get(value, part);
- return value;
- }
-
- template<int part=0, typename T, typename ...Args>
- void extract(T &nextpart, Args &...args)
- {
- assert(part < parts());
- get(nextpart,part);
- extract<part+1>(args...);
- }
-
- template<int part=0, typename T>
- void extract(T &nextpart)
- {
- assert(part < parts());
- get(nextpart,part);
- }
-
- // Raw get data operations, useful with data structures more than anything else
- // Warn: The message (well zmq) still 'owns' the data and will release it
- // when the message object is freed.
- template<typename Type>
- void get(Type*& value, size_t const part) const
- {
- value = static_cast<Type*>(raw_data(part));
- }
-
- // Warn: The message (well zmq) still 'owns' the data and will release it
- // when the message object is freed.
- template<typename Type>
- void get(Type** value, size_t const part) const
- {
- *value = static_cast<Type*>(raw_data(part));
- }
-
- // Move operators will take ownership of message parts without copying
- void move(void* part, size_t const size, release_function const& release);
-
- // Raw move data operation, useful with data structures more than anything else
- template<typename Object>
- void move(Object *part)
- {
- move(part, sizeof(Object), &deleter_callback<Object>);
- }
-
- // Copy operators will take copies of any data
- template<typename Type>
- void add(Type *part, size_t const size)
- {
- _parts.push_back( frame( part, size ) );
- }
-
-
- template<typename Type, typename ...Args>
- void add(Type const& part, Args &&...args)
- {
- *this << part;
- add(std::forward<Args>(args)...);
- }
-
- template<typename Type>
- void add(Type const part)
- {
- *this << part;
- }
-
- // Stream reader style
- void reset_read_cursor();
-
- template<typename Type>
- message& operator>>(Type& value)
- {
- get(value, _read_cursor++);
- return *this;
- }
-
- // Stream writer style - these all use copy styles
- message& operator<<(int8_t const integer);
- message& operator<<(int16_t const integer);
- message& operator<<(int32_t const integer);
- message& operator<<(int64_t const integer);
-
- message& operator<<(uint8_t const unsigned_integer);
- message& operator<<(uint16_t const unsigned_integer);
- message& operator<<(uint32_t const unsigned_integer);
- message& operator<<(uint64_t const unsigned_integer);
-
- message& operator<<(float const floating_point);
- message& operator<<(double const double_precision);
- message& operator<<(bool const boolean);
-
- message& operator<<(char const* c_string);
- message& operator<<(std::string const& string);
-
- // Queue manipulation
- void push_front(void const* part, size_t const size);
-
- // TODO: unify conversion of types with the stream operators
- void push_front(int8_t const integer);
- void push_front(int16_t const integer);
- void push_front(int32_t const integer);
- void push_front(int64_t const integer);
-
- void push_front(uint8_t const unsigned_integer);
- void push_front(uint16_t const unsigned_integer);
- void push_front(uint32_t const unsigned_integer);
- void push_front(uint64_t const unsigned_integer);
-
- void push_front(float const floating_point);
- void push_front(double const double_precision);
- void push_front(bool const boolean);
-
- void push_front(char const* c_string);
- void push_front(std::string const& string);
-
- void pop_front();
-
- void push_back(void const* part, size_t const size)
- {
- add( part, size );
- }
-
- template<typename Type>
- void push_back(Type const part)
- {
- *this << part;
- }
-
- void pop_back();
-
- void remove(size_t const part);
-
- // Move supporting
- message(message&& source) NOEXCEPT;
- message& operator=(message&& source) NOEXCEPT;
-
- // Copy support
- message copy() const;
- void copy(message const& source);
-
- // Used for internal tracking
- void sent(size_t const part);
-
- // Access to raw zmq details
- void const* raw_data(size_t const part = 0) const;
- zmq_msg_t& raw_msg(size_t const part = 0);
- zmq_msg_t& raw_new_msg();
- zmq_msg_t& raw_new_msg(size_t const reserve_data_size);
-
-private:
- typedef std::vector<frame> parts_type;
- parts_type _parts;
- size_t _read_cursor;
-
- // Disable implicit copy support, code must request a copy to clone
- message(message const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED;
- message& operator=(message const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED;
-
- static void release_callback(void* data, void* hint);
-
- template<typename Object>
- static void deleter_callback(void* data)
- {
- delete static_cast<Object*>(data);
- }
-};
-
-}
-
-#endif /* ZMQPP_MESSAGE_HPP_ */
diff --git a/dep/zmqpp/zmqpp/poller.cpp b/dep/zmqpp/zmqpp/poller.cpp
deleted file mode 100644
index a6340c9bd61..00000000000
--- a/dep/zmqpp/zmqpp/poller.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Created on: 16 Aug 2011
- * Author: Ben Gray (@benjamg)
- */
-
-#include "exception.hpp"
-#include "socket.hpp"
-#include "poller.hpp"
-
-#include <zmq.h>
-
-namespace zmqpp
-{
-
-const long poller::wait_forever = -1;
-const short poller::poll_none = 0;
-const short poller::poll_in = ZMQ_POLLIN;
-const short poller::poll_out = ZMQ_POLLOUT;
-const short poller::poll_error = ZMQ_POLLERR;
-
-poller::poller()
- : _items()
- , _index()
- , _fdindex()
-{
-
-}
-
-poller::~poller()
-{
- _items.clear();
- _index.clear();
- _fdindex.clear();
-}
-
-void poller::add(socket& socket, short const event /* = POLL_IN */)
-{
- zmq_pollitem_t item { socket, 0, event, 0 };
-
- size_t index = _items.size();
- _items.push_back(item);
- _index[socket] = index;
-}
-
-void poller::add(int const descriptor, short const event /* = POLL_IN */)
-{
- zmq_pollitem_t item { nullptr, descriptor, event, 0 };
-
- size_t index = _items.size();
- _items.push_back(item);
- _fdindex[descriptor] = index;
-}
-
-bool poller::has(socket_t const& socket)
-{
- return _index.find(socket) != _index.end();
-}
-
-bool poller::has(int const descriptor)
-{
- return _fdindex.find(descriptor) != _fdindex.end();
-}
-
-void poller::reindex(size_t const index)
-{
- if ( nullptr != _items[index].socket )
- {
- auto found = _index.find( _items[index].socket );
- if (_index.end() == found) { throw exception("unable to reindex socket in poller"); }
- found->second = index;
- }
- else
- {
- auto found = _fdindex.find( _items[index].fd );
- if (_fdindex.end() == found) { throw exception("unable to reindex file descriptor in poller"); }
- found->second = index;
- }
-}
-
-void poller::remove(socket_t const& socket)
-{
- auto found = _index.find(socket);
- if (_index.end() == found) { return; }
-
- if ( _items.size() - 1 == found->second )
- {
- _items.pop_back();
- _index.erase(found);
- return;
- }
-
- std::swap(_items[found->second], _items.back());
- _items.pop_back();
-
- auto index = found->second;
- _index.erase(found);
-
- reindex( index );
-}
-
-void poller::remove(int const descriptor)
-{
- auto found = _fdindex.find(descriptor);
- if (_fdindex.end() == found) { return; }
-
- if ( _items.size() - 1 == found->second )
- {
- _items.pop_back();
- _fdindex.erase(found);
- return;
- }
-
- std::swap(_items[found->second], _items.back());
- _items.pop_back();
-
- auto index = found->second;
- _fdindex.erase(found);
-
- reindex( index );
-}
-
-void poller::check_for(socket const& socket, short const event)
-{
- auto found = _index.find(socket);
- if (_index.end() == found)
- {
- throw exception("this socket is not represented within this poller");
- }
-
- _items[found->second].events = event;
-}
-
-void poller::check_for(int const descriptor, short const event)
-{
- auto found = _fdindex.find(descriptor);
- if (_fdindex.end() == found)
- {
- throw exception("this socket is not represented within this poller");
- }
-
- _items[found->second].events = event;
-}
-
-bool poller::poll(long timeout /* = WAIT_FOREVER */)
-{
- int result = zmq_poll(_items.data(), _items.size(), timeout);
- if (result < 0)
- {
- if(EINTR == zmq_errno())
- {
- return false;
- }
-
- throw zmq_internal_exception();
- }
-
- return (result > 0);
-}
-
-short poller::events(socket const& socket) const
-{
- auto found = _index.find(socket);
- if (_index.end() == found)
- {
- throw exception("this socket is not represented within this poller");
- }
-
- return _items[found->second].revents;
-}
-
-short poller::events(int const descriptor) const
-{
- auto found = _fdindex.find(descriptor);
- if (_fdindex.end() == found)
- {
- throw exception("this file descriptor is not represented within this poller");
- }
-
- return _items[found->second].revents;
-}
-
-}
diff --git a/dep/zmqpp/zmqpp/poller.hpp b/dep/zmqpp/zmqpp/poller.hpp
deleted file mode 100644
index a19063a091d..00000000000
--- a/dep/zmqpp/zmqpp/poller.hpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/**
- * \file
- *
- * \date 9 Aug 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_POLLER_HPP_
-#define ZMQPP_POLLER_HPP_
-
-#include <unordered_map>
-#include <vector>
-
-#include "compatibility.hpp"
-
-namespace zmqpp
-{
-
-class socket;
-typedef socket socket_t;
-
-/*!
- * Polling wrapper.
- *
- * Allows access to polling for any number of sockets or file descriptors.
- */
-class poller
-{
-public:
- static const long wait_forever; /*!< Block forever flag, default setting. */
-
- static const short poll_none; /*!< No polling flags set. */
- static const short poll_in; /*!< Monitor inbound flag. */
- static const short poll_out; /*!< Monitor output flag. */
- static const short poll_error; /*!< Monitor error flag.\n Only for file descriptors. */
-
- /*!
- * Construct an empty polling model.
- */
- poller();
-
- /*!
- * Cleanup poller.
- *
- * Any sockets will need to be closed separately.
- */
- ~poller();
-
- /*!
- * Add a socket to the polling model and set which events to monitor.
- *
- * \param socket the socket to monitor.
- * \param event the event flags to monitor on the socket.
- */
- void add(socket_t& socket, short const event = poll_in);
-
- /*!
- * Add a file descriptor to the polling model and set which events to monitor.
- *
- * \param descriptor the file descriptor to monitor.
- * \param event the event flags to monitor.
- */
- void add(int const descriptor, short const event = poll_in | poll_error);
-
- /*!
- * Check if we are monitoring a given socket with this poller.
- *
- * \param socket the socket to check.
- * \return true if it is there.
- */
- bool has(socket_t const& socket);
-
- /*!
- * Check if we are monitoring a given file descriptor with this poller.
- *
- * \param descriptor the file descriptor to check.
- * \return true if it is there.
- */
- bool has(int const descriptor);
-
- /*!
- * Stop monitoring a socket.
- *
- * \param socket the socket to stop monitoring.
- */
- void remove(socket_t const& socket);
-
- /*!
- * Stop monitoring a file descriptor.
- *
- * \param descriptor the file descriptor to stop monitoring.
- */
- void remove(int const descriptor);
-
- /*!
- * Update the monitored event flags for a given socket.
- *
- * \param socket the socket to update event flags.
- * \param event the event flags to monitor on the socket.
- */
- void check_for(socket_t const& socket, short const event);
-
- /*!
- * Update the monitored event flags for a given file descriptor.
- *
- * \param descriptor the file descriptor to update event flags.
- * \param event the event flags to monitor on the socket.
- */
- void check_for(int const descriptor, short const event);
-
- /*!
- * Poll for monitored events.
- *
- * By default this method will block forever or until at least one of the monitored
- * sockets or file descriptors has events.
- *
- * If a timeout is set and was reached then this function returns false.
- *
- * \param timeout milliseconds to timeout.
- * \return true if there is an event..
- */
- bool poll(long timeout = wait_forever);
-
- /*!
- * Get the event flags triggered for a socket.
- *
- * \param socket the socket to get triggered event flags for.
- * \return the event flags.
- */
- short events(socket_t const& socket) const;
-
- /*!
- * Get the event flags triggered for a file descriptor.
- *
- * \param descriptor the file descriptor to get triggered event flags for.
- * \return the event flags.
- */
- short events(int const descriptor) const;
-
- /*!
- * Check either a file descriptor or socket for input events.
- *
- * Templated helper method that calls through to event and checks for a given flag
- *
- * \param watchable either a file descriptor or socket known to the poller.
- * \return true if there is input.
- */
- template<typename Watched>
- bool has_input(Watched const& watchable) const { return events(watchable) & poll_in; }
-
- /*!
- * Check either a file descriptor or socket for output events.
- *
- * Templated helper method that calls through to event and checks for a given flag
- *
- * \param watchable either a file descriptor or socket known to the poller.
- * \return true if there is output.
- */
- template<typename Watched>
- bool has_output(Watched const& watchable) const { return events(watchable) & poll_out; }
-
- /*!
- * Check a file descriptor.
- *
- * Templated helper method that calls through to event and checks for a given flag
- *
- * Technically this template works for sockets as well but the error flag is never set for
- * sockets so I have no idea why someone would call it.
- *
- * \param watchable a file descriptor know to the poller.
- * \return true if there is an error.
- */
- template<typename Watched>
- bool has_error(Watched const& watchable) const { return events(watchable) & poll_error; }
-
-private:
- std::vector<zmq_pollitem_t> _items;
- std::unordered_map<void *, size_t> _index;
- std::unordered_map<int, size_t> _fdindex;
-
- void reindex(size_t const index);
-};
-
-}
-
-#endif /* ZMQPP_POLLER_HPP_ */
diff --git a/dep/zmqpp/zmqpp/socket.cpp b/dep/zmqpp/zmqpp/socket.cpp
deleted file mode 100644
index 8b4efe4f1d2..00000000000
--- a/dep/zmqpp/zmqpp/socket.cpp
+++ /dev/null
@@ -1,762 +0,0 @@
-/*
- * Created on: 9 Aug 2011
- * Author: Ben Gray (@benjamg)
- */
-
-#include <array>
-#include <cassert>
-#include <cstring>
-#include <functional>
-
-#include "context.hpp"
-#include "exception.hpp"
-#include "message.hpp"
-#include "socket.hpp"
-
-namespace zmqpp
-{
-
-const int socket::normal = 0;
-#if (ZMQ_VERSION_MAJOR == 2)
-const int socket::dont_wait = ZMQ_NOBLOCK;
-#else
-const int socket::dont_wait = ZMQ_DONTWAIT;
-#endif
-const int socket::send_more = ZMQ_SNDMORE;
-#ifdef ZMQ_EXPERIMENTAL_LABELS
-const int socket::send_label = ZMQ_SNDLABEL;
-#endif
-
-const int max_socket_option_buffer_size = 256;
-const int max_stream_buffer_size = 4096;
-
-socket::socket(const context& context, socket_type const type)
- : _socket(nullptr)
- , _type(type)
- , _recv_buffer()
-{
- _socket = zmq_socket(context, static_cast<int>(type));
- if(nullptr == _socket)
- {
- throw zmq_internal_exception();
- }
-
- zmq_msg_init(&_recv_buffer);
-}
-
-socket::~socket()
-{
- zmq_msg_close(&_recv_buffer);
-
- if (nullptr != _socket)
- {
-
-#ifndef NDEBUG // unused assert variable in release
- int result = zmq_close(_socket);
- assert(0 == result);
-#else
- zmq_close(_socket);
-#endif // NDEBUG
-
- _socket = nullptr;
- }
-}
-
-void socket::bind(endpoint_t const& endpoint)
-{
- int result = zmq_bind(_socket, endpoint.c_str());
-
- if (0 != result)
- {
- throw zmq_internal_exception();
- }
-}
-
-void socket::unbind(endpoint_t const& endpoint)
-{
-#if (ZMQ_VERSION_MAJOR > 3 || (ZMQ_VERSION_MAJOR == 3 && ZMQ_VERSION_MINOR >= 2))
- int result = zmq_unbind(_socket, endpoint.c_str());
-
- if (0 != result)
- {
- throw zmq_internal_exception();
- }
-#endif
-}
-
-void socket::connect(endpoint_t const& endpoint)
-{
- int result = zmq_connect(_socket, endpoint.c_str());
-
- if (0 != result)
- {
- throw zmq_internal_exception();
- }
-}
-
-void socket::disconnect(endpoint_t const& endpoint)
-{
-#if (ZMQ_VERSION_MAJOR > 3 || (ZMQ_VERSION_MAJOR == 3 && ZMQ_VERSION_MINOR >= 2))
- int result = zmq_disconnect(_socket, endpoint.c_str());
-
- if (0 != result)
- {
- throw zmq_internal_exception();
- }
-#endif
-}
-
-void socket::close()
-{
- int result = zmq_close(_socket);
-
- if (0 != result)
- {
- throw zmq_internal_exception();
- }
-
- _socket = nullptr;
-}
-
-bool socket::send(message& message, bool const dont_block /* = false */)
-{
- size_t parts = message.parts();
- if (parts == 0)
- {
- throw std::invalid_argument("sending requires messages have at least one part");
- }
-
- bool dont_wait = dont_block;
- for(size_t i = 0; i < parts; ++i)
- {
- int flag = socket::normal;
- if(dont_wait) { flag |= socket::dont_wait; }
- if(i < (parts - 1)) { flag |= socket::send_more; }
-
-#if (ZMQ_VERSION_MAJOR == 2)
- int result = zmq_send( _socket, &message.raw_msg(i), flag );
-#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2))
- int result = zmq_sendmsg( _socket, &message.raw_msg(i), flag );
-#else
- int result = zmq_msg_send( &message.raw_msg(i), _socket, flag );
-#endif
-
- if (result < 0)
- {
- // the zmq framework should not block if the first part is accepted
- // so we should only ever get this error on the first part
- if((0 == i) && (EAGAIN == zmq_errno()))
- {
- return false;
- }
-
- if(EINTR == zmq_errno())
- {
- if (0 == message.parts())
- {
- return false;
- }
-
- // If we have an interrupt but it's not on the first part then we
- // know we can safely send out the rest of the message as we can
- // enforce that it won't wait on a blocking action
- dont_wait = true;
- continue;
- }
-
- // sanity checking
- assert(EAGAIN != zmq_errno());
-
- throw zmq_internal_exception();
- }
-
- message.sent(i);
- }
-
- // Leave message reference in a stable state
- zmqpp::message local;
- std::swap(local, message);
- return true;
-}
-
-bool socket::receive(message& message, bool const dont_block /* = false */)
-{
- if (message.parts() > 0)
- {
- // swap and discard old message
- zmqpp::message local;
- std::swap(local, message);
- }
-
- int flags = (dont_block) ? socket::dont_wait : socket::normal;
- bool more = true;
-
- while(more)
- {
-#if (ZMQ_VERSION_MAJOR == 2)
- int result = zmq_recv( _socket, &_recv_buffer, flags );
-#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2))
- int result = zmq_recvmsg( _socket, &_recv_buffer, flags );
-#else
- int result = zmq_msg_recv( &_recv_buffer, _socket, flags );
-#endif
-
- if(result < 0)
- {
- if ((0 == message.parts()) && (EAGAIN == zmq_errno()))
- {
- return false;
- }
-
- if(EINTR == zmq_errno())
- {
- if (0 == message.parts())
- {
- return false;
- }
-
- // If we have an interrupt but it's not on the first part then we
- // know we can safely pull out the rest of the message as it will
- // not be blocking
- continue;
- }
-
- assert(EAGAIN != zmq_errno());
-
- throw zmq_internal_exception();
- }
-
- zmq_msg_t& dest = message.raw_new_msg();
- zmq_msg_move(&dest, &_recv_buffer);
-
- get(socket_option::receive_more, more);
- }
-
- return true;
-}
-
-
-bool socket::send(std::string const& string, int const flags /* = NORMAL */)
-{
- return send_raw(string.data(), string.size(), flags);
-}
-
-bool socket::receive(std::string& string, int const flags /* = NORMAL */)
-{
-#if (ZMQ_VERSION_MAJOR == 2)
- int result = zmq_recv( _socket, &_recv_buffer, flags );
-#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2))
- int result = zmq_recvmsg( _socket, &_recv_buffer, flags );
-#else
- int result = zmq_msg_recv( &_recv_buffer, _socket, flags );
-#endif
-
- if(result >= 0)
- {
- string.reserve(zmq_msg_size(&_recv_buffer));
- string.assign(static_cast<char*>(zmq_msg_data(&_recv_buffer)), zmq_msg_size(&_recv_buffer));
-
- return true;
- }
-
- if (EAGAIN == zmq_errno() || EINTR == zmq_errno())
- {
- return false;
- }
-
- throw zmq_internal_exception();
-}
-
-
-bool socket::send_raw(char const* buffer, int const length, int const flags /* = NORMAL */)
-{
-#if (ZMQ_VERSION_MAJOR == 2)
- zmq_msg_t msg;
- int result = zmq_msg_init_size(&msg, length);
- if (result != 0)
- {
- zmq_internal_exception();
- }
-
- memcpy(zmq_msg_data(&msg), buffer, length);
- result = zmq_send(_socket, &msg, flags);
-#else
- int result = zmq_send(_socket, buffer, length, flags);
-#endif
- if(result >= 0)
- {
- return true;
- }
-
-#if (ZMQ_VERSION_MAJOR == 2)
- // only actually need to close this on error
- zmq_msg_close(&msg);
-#endif
-
- if (EAGAIN == zmq_errno() || EINTR == zmq_errno())
- {
- return false;
- }
-
- throw zmq_internal_exception();
-}
-
-bool socket::receive_raw(char* buffer, int& length, int const flags /* = NORMAL */)
-{
-#if (ZMQ_VERSION_MAJOR == 2)
- int result = zmq_recv( _socket, &_recv_buffer, flags );
-#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2))
- int result = zmq_recvmsg( _socket, &_recv_buffer, flags );
-#else
- int result = zmq_msg_recv( &_recv_buffer, _socket, flags );
-#endif
-
- if(result >= 0)
- {
- length = zmq_msg_size(&_recv_buffer);
- memcpy(buffer, zmq_msg_data(&_recv_buffer), length);
-
- return true;
- }
-
- if (EAGAIN == zmq_errno() || EINTR == zmq_errno())
- {
- return false;
- }
-
- throw zmq_internal_exception();
-}
-
-
-// Helper
-void socket::subscribe(std::string const& topic)
-{
- set(socket_option::subscribe, topic);
-}
-
-void socket::unsubscribe(std::string const& topic)
-{
- set(socket_option::unsubscribe, topic);
-}
-
-bool socket::has_more_parts() const
-{
- return get<bool>(socket_option::receive_more);
-}
-
-
-// Set socket options for different types of option
-void socket::set(socket_option const option, int const value)
-{
- switch(option)
- {
- // unsigned 64bit Integers
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::high_water_mark:
- case socket_option::send_buffer_size:
- case socket_option::receive_buffer_size:
-#endif
- case socket_option::affinity:
- if (value < 0) { throw exception("attempting to set an unsigned 64 bit integer option with a negative integer"); }
- set(option, static_cast<uint64_t>(value));
- break;
-
- // 64bit Integers
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::rate:
- case socket_option::recovery_interval:
- case socket_option::recovery_interval_seconds:
- case socket_option::swap_size:
-#else
- case socket_option::max_messsage_size:
-#endif
- set(option, static_cast<int64_t>(value));
- break;
-
- // Boolean
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1))
- case socket_option::ipv4_only:
-#endif
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::multicast_loopback:
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
-#if (ZMQ_VERSION_MINOR == 2)
- case socket_option::delay_attach_on_connect:
-#else
- case socket_option::immediate:
-#endif
- case socket_option::router_mandatory:
- case socket_option::xpub_verbose:
-#endif
- if (value == 0) { set(option, false); }
- else if (value == 1) { set(option, true); }
- else { throw exception("attempting to set a boolean option with a non 0 or 1 integer"); }
- break;
-
- // Default or Boolean
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
- case socket_option::tcp_keepalive:
- if (value < -1 || value > 1) { throw exception("attempting to set a default or boolean option with a non -1, 0 or 1 integer"); }
- if (0 != zmq_setsockopt(_socket, static_cast<int>(option), &value, sizeof(value)))
- {
- throw zmq_internal_exception();
- }
- break;
-#endif
-
- // Integers that require +ve numbers
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::reconnect_interval_max:
-#else
- case socket_option::reconnect_interval_max:
- case socket_option::send_buffer_size:
- case socket_option::recovery_interval:
- case socket_option::receive_buffer_size:
- case socket_option::send_high_water_mark:
- case socket_option::receive_high_water_mark:
- case socket_option::multicast_hops:
- case socket_option::rate:
-#endif
- case socket_option::backlog:
- if (value < 0) { throw exception("attempting to set a positive only integer option with a negative integer"); }
- // Integers
- case socket_option::reconnect_interval:
- case socket_option::linger:
- case socket_option::receive_timeout:
- case socket_option::send_timeout:
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
- case socket_option::tcp_keepalive_idle:
- case socket_option::tcp_keepalive_count:
- case socket_option::tcp_keepalive_interval:
-#endif
- if (0 != zmq_setsockopt(_socket, static_cast<int>(option), &value, sizeof(value)))
- {
- throw zmq_internal_exception();
- }
- break;
- default:
- throw exception("attempting to set a non signed integer option with a signed integer value");
- }
-}
-
-void socket::set(socket_option const option, bool const value)
-{
- switch(option)
- {
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::multicast_loopback:
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1))
- case socket_option::ipv4_only:
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
-#if (ZMQ_VERSION_MINOR == 2)
- case socket_option::delay_attach_on_connect:
-#else
- case socket_option::immediate:
-#endif
- case socket_option::router_mandatory:
- case socket_option::xpub_verbose:
-#endif
- {
- int ivalue = value ? 1 : 0;
- if (0 != zmq_setsockopt(_socket, static_cast<int>(option), &ivalue, sizeof(ivalue)))
- {
- throw zmq_internal_exception();
- }
- break;
- }
- default:
- throw exception("attempting to set a non boolean option with a boolean value");
- }
-}
-
-void socket::set(socket_option const option, uint64_t const value)
-{
- switch(option)
- {
-#if (ZMQ_VERSION_MAJOR == 2)
- // unsigned 64bit Integers
- case socket_option::high_water_mark:
- case socket_option::send_buffer_size:
- case socket_option::receive_buffer_size:
-#endif
- case socket_option::affinity:
- if (0 != zmq_setsockopt(_socket, static_cast<int>(option), &value, sizeof(value)))
- {
- throw zmq_internal_exception();
- }
- break;
- default:
- throw exception("attempting to set a non unsigned 64 bit integer option with a unsigned 64 bit integer value");
- }
-}
-
-void socket::set(socket_option const option, int64_t const value)
-{
- switch(option)
- {
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::rate:
- case socket_option::recovery_interval:
- case socket_option::recovery_interval_seconds:
- case socket_option::swap_size:
-#else
- case socket_option::max_messsage_size:
-#endif
- // zmq only allowed +ve int64_t options
- if (value < 0) { throw exception("attempting to set a positive only 64 bit integer option with a negative 64bit integer"); }
- if (0 != zmq_setsockopt(_socket, static_cast<int>(option), &value, sizeof(value)))
- {
- throw zmq_internal_exception();
- }
- break;
- default:
- throw exception("attempting to set a non 64 bit integer option with a 64 bit integer value");
- }
-}
-
-void socket::set(socket_option const option, char const* value, size_t const length)
-{
- switch(option)
- {
- case socket_option::identity:
- case socket_option::subscribe:
- case socket_option::unsubscribe:
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
- case socket_option::tcp_accept_filter:
-#endif
- if (0 != zmq_setsockopt(_socket, static_cast<int>(option), value, length))
- {
- throw zmq_internal_exception();
- }
- break;
- default:
- throw exception("attempting to set a non string option with a string value");
- }
-}
-
-// Get socket options, multiple versions for easy of use
-void socket::get(socket_option const option, int& value) const
-{
- size_t value_size = sizeof(int);
-
- switch(option)
- {
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::receive_more:
- case socket_option::multicast_loopback:
- value = static_cast<int>(get<int64_t>(option));
- break;
-#endif
- case socket_option::type:
- case socket_option::linger:
- case socket_option::backlog:
- case socket_option::reconnect_interval:
- case socket_option::reconnect_interval_max:
- case socket_option::receive_timeout:
- case socket_option::send_timeout:
- case socket_option::file_descriptor:
- case socket_option::events:
-#if (ZMQ_VERSION_MAJOR > 2)
- case socket_option::receive_more:
- case socket_option::send_buffer_size:
- case socket_option::receive_buffer_size:
- case socket_option::rate:
- case socket_option::recovery_interval:
- case socket_option::send_high_water_mark:
- case socket_option::receive_high_water_mark:
- case socket_option::multicast_hops:
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1))
- case socket_option::ipv4_only:
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
-#if (ZMQ_VERSION_MINOR == 2)
- case socket_option::delay_attach_on_connect:
-#else
- case socket_option::immediate:
-#endif
- case socket_option::tcp_keepalive:
- case socket_option::tcp_keepalive_idle:
- case socket_option::tcp_keepalive_count:
- case socket_option::tcp_keepalive_interval:
-#endif
-#ifdef ZMQ_EXPERIMENTAL_LABELS
- case socket_option::receive_label:
-#endif
- if (0 != zmq_getsockopt(_socket, static_cast<int>(option), &value, &value_size))
- {
- throw zmq_internal_exception();
- }
-
- // sanity check
- assert(value_size <= sizeof(int));
- break;
- default:
- throw exception("attempting to get a non integer option with an integer value");
- }
-}
-
-void socket::get(socket_option const option, bool& value) const
-{
-#if (ZMQ_VERSION_MAJOR == 2)
- int64_t int_value = 0;
- size_t value_size = sizeof(int64_t);
-#else
- int int_value = 0;
- size_t value_size = sizeof(int);
-#endif
-
- switch(option)
- {
- case socket_option::receive_more:
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::multicast_loopback:
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1))
- case socket_option::ipv4_only:
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
-#if (ZMQ_VERSION_MINOR == 2)
- case socket_option::delay_attach_on_connect:
-#else
- case socket_option::immediate:
-#endif
-#endif
-#ifdef ZMQ_EXPERIMENTAL_LABELS
- case socket_option::receive_label:
-#endif
- if (0 != zmq_getsockopt(_socket, static_cast<int>(option), &int_value, &value_size))
- {
- throw zmq_internal_exception();
- }
-
- value = (int_value == 1) ? true : false;
- break;
- default:
- throw exception("attempting to get a non boolean option with a boolean value");
- }
-}
-
-void socket::get(socket_option const option, uint64_t& value) const
-{
- size_t value_size = sizeof(uint64_t);
-
- switch(option)
- {
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::high_water_mark:
- case socket_option::send_buffer_size:
- case socket_option::receive_buffer_size:
-#endif
- case socket_option::affinity:
- if(0 != zmq_getsockopt(_socket, static_cast<int>(option), &value, &value_size))
- {
- throw zmq_internal_exception();
- }
- break;
- default:
- throw exception("attempting to get a non unsigned 64 bit integer option with an unsigned 64 bit integer value");
- }
-}
-
-void socket::get(socket_option const option, int64_t& value) const
-{
- size_t value_size = sizeof(int64_t);
-
- switch(option)
- {
-#if (ZMQ_VERSION_MAJOR == 2)
- case socket_option::rate:
- case socket_option::recovery_interval:
- case socket_option::recovery_interval_seconds:
- case socket_option::swap_size:
- case socket_option::receive_more:
- case socket_option::multicast_loopback:
-#else
- case socket_option::max_messsage_size:
-#endif
- if(0 != zmq_getsockopt(_socket, static_cast<int>(option), &value, &value_size))
- {
- throw zmq_internal_exception();
- }
- break;
- default:
- throw exception("attempting to get a non 64 bit integer option with an 64 bit integer value");
- }
-}
-
-void socket::get(socket_option const option, std::string& value) const
-{
- static std::array<char, max_socket_option_buffer_size> buffer;
- size_t size = max_socket_option_buffer_size;
-
- switch(option)
- {
- case socket_option::identity:
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
- case socket_option::last_endpoint:
-#endif
- if(0 != zmq_getsockopt(_socket, static_cast<int>(option), buffer.data(), &size))
- {
- throw zmq_internal_exception();
- }
-
- value.assign(buffer.data(), size);
- break;
- default:
- throw exception("attempting to get a non string option with a string value");
- }
-}
-
-socket::socket(socket&& source) NOEXCEPT
- : _socket(source._socket)
- , _type(source._type)
- , _recv_buffer()
-{
- // we steal the zmq_msg_t from the valid socket, we only init our own because it's cheap
- // and zmq_msg_move does a valid check
- zmq_msg_init(&_recv_buffer);
- zmq_msg_move(&_recv_buffer, &source._recv_buffer);
-
- // Clean up source a little, we will handle the deinit, it doesn't need to
- source._socket = nullptr;
-}
-
-socket& socket::operator=(socket&& source) NOEXCEPT
-{
- std::swap(_socket, source._socket);
-
- _type = source._type; // just clone?
-
- // we steal the zmq_msg_t from the valid socket, we only init our own because it's cheap
- // and zmq_msg_move does a valid check
- zmq_msg_init(&_recv_buffer);
- zmq_msg_move(&_recv_buffer, &source._recv_buffer);
-
- return *this;
-}
-
-
-socket::operator bool() const
-{
- return nullptr != _socket;
-}
-
-
-socket::operator void*() const
-{
- return _socket;
-}
-
-void socket::track_message(message const& /* message */, uint32_t const parts, bool& should_delete)
-{
- if (parts == 0)
- {
- should_delete = true;
- }
-}
-
-}
diff --git a/dep/zmqpp/zmqpp/socket.hpp b/dep/zmqpp/zmqpp/socket.hpp
deleted file mode 100644
index 279bf801f77..00000000000
--- a/dep/zmqpp/zmqpp/socket.hpp
+++ /dev/null
@@ -1,500 +0,0 @@
-/**
- * \file
- *
- * \date 9 Aug 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_SOCKET_HPP_
-#define ZMQPP_SOCKET_HPP_
-
-#include <cstring>
-#include <string>
-#include <list>
-
-#include <zmq.h>
-
-#include "compatibility.hpp"
-
-#include "socket_types.hpp"
-#include "socket_options.hpp"
-
-namespace zmqpp
-{
-
-class context;
-class message;
-
-typedef std::string endpoint_t;
-typedef context context_t;
-typedef message message_t;
-
-/*!
- * The socket class represents the zmq sockets.
- *
- * A socket can be bound and/or connected to as many endpoints as required
- * with the sole exception of a ::pair socket.
- *
- * The routing is handled by zmq based on the type set.
- *
- * The bound side of an inproc connection must occur first and inproc can only
- * connect to other inproc sockets of the same context.
- *
- * This class is c++0x move supporting and cannot be copied.
- */
-class socket
-{
-public:
- static const int normal; /*!< /brief default send type, no flags set */
-#if (ZMQ_VERSION_MAJOR == 2)
- static const int dont_wait; /*!< /brief don't block if sending is not currently possible */
-#else
- static const int dont_wait; /*!< /brief don't block if sending is not currently possible */
-#endif
- static const int send_more; /*!< /brief more parts will follow this one */
-#ifdef ZMQ_EXPERIMENTAL_LABELS
- static const int send_label; /*!< /brief this message part is an internal zmq label */
-#endif
-
- /*!
- * Create a socket for a given type.
- *
- * \param context the zmq context under which the socket will live
- * \param type a valid ::socket_type for the socket
- */
- socket(context_t const& context, socket_type const type);
-
- /*!
- * This will close any socket still open before returning
- */
- ~socket();
-
- /*!
- * Get the type of the socket, this works on zmqpp types and not the zmq internal types.
- * Use the socket::get method if you wish to intergoate the zmq internal ones.
- *
- * \return the type of the socket
- */
- socket_type type() const { return _type; }
-
- /*!
- * Asynchronously binds to an endpoint.
- *
- * \param endpoint the zmq endpoint to bind to
- */
- void bind(endpoint_t const& endpoint);
-
- /*!
- * Unbinds from a previously bound endpoint.
- *
- * \param endpoint the zmq endpoint to bind to
- */
- void unbind(endpoint_t const& endpoint);
-
- /*!
- * Asynchronously connects to an endpoint.
- * If the endpoint is not inproc then zmq will happily keep trying
- * to connect until there is something there.
- *
- * Inproc sockets must have a valid target already bound before connection
- * will work.
- *
- * \param endpoint the zmq endpoint to connect to
- */
- void connect(endpoint_t const& endpoint);
-
- /*!
- * Asynchronously connects to multiple endpoints.
- * If the endpoint is not inproc then zmq will happily keep trying
- * to connect until there is something there.
- *
- * Inproc sockets must have a valid target already bound before connection
- * will work.
- *
- * This is a helper function that wraps the single item connect in a loop
- *
- * \param connections_begin the starting iterator for zmq endpoints.
- * \param connections_end the final iterator for zmq endpoints.
- */
- template<typename InputIterator>
- void connect(InputIterator const& connections_begin, InputIterator const& connections_end)
- {
- for(InputIterator it = connections_begin; it != connections_end; ++it)
- {
- connect(*it);
- }
- }
-
-
- /*!
- * Disconnects a previously connected endpoint.
- *
- * \param endpoint the zmq endpoint to disconnect from
- */
- void disconnect(endpoint_t const& endpoint);
-
- /*!
- * Disconnects from multiple previously connected endpoints.
- *
- * This is a helper function that wraps the single item disconnect in a loop
- *
- * \param disconnections_begin the starting iterator for zmq endpoints.
- * \param disconnections_end the final iterator for zmq endpoints.
- */
- template<typename InputIterator>
- void disconnect(InputIterator const& disconnections_begin, InputIterator const& disconnections_end)
- {
- for(InputIterator it = disconnections_begin; it != disconnections_end; ++it)
- {
- disconnect(*it);
- }
- }
-
- /*!
- * Closes the internal zmq socket and marks this instance
- * as invalid.
- */
- void close();
-
- /*!
- * Sends the message over the connection, this may be a multipart message.
- *
- * If dont_block is true and we are unable to add a new message then this
- * function will return false.
- *
- * \param message message to send
- * \param dont_block boolean to dictate if we wait while sending.
- * \return true if message sent, false if it would have blocked
- */
- bool send(message_t& message, bool const dont_block = false);
-
- /*!
- * Gets a message from the connection, this may be a multipart message.
- *
- * If dont_block is true and we are unable to get a message then this
- * function will return false.
- *
- * \param message reference to fill with received data
- * \param dont_block boolean to dictate if we wait for data.
- * \return true if message sent, false if it would have blocked
- */
- bool receive(message_t& message, bool const dont_block = false);
-
- /*!
- * Sends the byte data held by the string as the next message part.
- *
- * If the socket::DONT_WAIT flag and we are unable to add a new message to
- * socket then this function will return false.
- *
- * \param string message part to send
- * \param flags message send flags
- * \return true if message part sent, false if it would have blocked
- */
- bool send(std::string const& string, int const flags = normal);
-
- /*!
- * If there is a message ready then get the next part as a string
- *
- * If the socket::DONT_WAIT flag and there is no message ready to receive
- * then this function will return false.
- *
- * \param string message part to receive into
- * \param flags message receive flags
- * \return true if message part received, false if it would have blocked
- */
- bool receive(std::string& string, int const flags = normal);
-
- /*!
- * Sends the byte data pointed to by buffer as the next part of the message.
- *
- * If the socket::DONT_WAIT flag and we are unable to add a new message to
- * socket then this function will return false.
- *
- * \param buffer byte buffer pointer to start writing from
- * \param length max length of the buffer
- * \param flags message send flags
- * \return true if message part sent, false if it would have blocked
- */
- bool send_raw(char const* buffer, int const length, int const flags = normal);
-
- /*!
- * \warning If the buffer is not large enough for the message part then the
- * data will be truncated. The rest of the part is lost forever.
- *
- * If there is a message ready then get the next part of it as a raw
- * byte buffer.
- *
- * If the socket::DONT_WAIT flag and there is no message ready to receive
- * then this function will return false.
- *
- * \param buffer byte buffer pointer to start writing to
- * \param length max length of the buffer
- * \param flags message receive flags
- * \return true if message part received, false if it would have blocked
- */
- bool receive_raw(char* buffer, int& length, int const flags = normal);
-
- /*!
- *
- * Subscribe to a topic
- *
- * Helper function that is equivalent of calling
- * \code
- * set(zmqpp::socket_option::subscribe, topic);
- * \endcode
- *
- * This method is only useful for subscribe type sockets.
- *
- * \param topic the topic to subscribe to.
- */
- void subscribe(std::string const& topic);
-
- /*!
- * Subscribe to a topic
- *
- * Helper function that is equivalent of a loop calling
- * \code
- * set(zmqpp::socket_option::subscribe, topic);
- * \endcode
- *
- * This method is only useful for subscribe type sockets.
- *
- * Generally this will be used with stl collections using begin() and
- * end() functions to get the iterators.
- * For this reason the end loop runs until the end iterator, not inclusive
- * of it.
- *
- * \param topics_begin the starting iterator for topics.
- * \param topics_end the final iterator for topics.
- */
- template<typename InputIterator>
- void subscribe(InputIterator const& topics_begin, InputIterator const& topics_end)
- {
- for(InputIterator it = topics_begin; it != topics_end; ++it)
- {
- subscribe(*it);
- }
- }
-
- /*!
- * Unsubscribe from a topic
- *
- * Helper function that is equivalent of calling
- * \code
- * set(zmqpp::socket_option::unsubscribe, topic);
- * \endcode
- *
- * This method is only useful for subscribe type sockets.
- *
- * \param topic the topic to unsubscribe from.
- */
- void unsubscribe(std::string const& topic);
-
- /*!
- * Unsubscribe from a topic
- *
- * Helper function that is equivalent of a loop calling
- * \code
- * set(zmqpp::socket_option::unsubscribe, topic);
- * \endcode
- *
- * This method is only useful for subscribe type sockets.
- *
- * Generally this will be used with stl collections using begin() and
- * end() functions to get the iterators.
- * For this reason the end loop runs until the end iterator, not inclusive
- * of it.
- *
- * \param topics_begin the starting iterator for topics.
- * \param topics_end the final iterator for topics.
- */
- template<typename InputIterator>
- void unsubscribe(InputIterator const& topics_begin, InputIterator const& topics_end)
- {
- for(InputIterator it = topics_begin; it != topics_end; ++it)
- {
- unsubscribe(*it);
- }
- }
-
- /*!
- * If the last receive part call to the socket resulted
- * in a label or a non-terminating part of a multipart
- * message this will return true.
- *
- * \return true if there are more parts
- */
- bool has_more_parts() const;
-
- /*!
- * Set the value of an option in the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value to set the option to
- */
- void set(socket_option const option, int const value);
-
- /*!
- * Set the value of an option in the underlaying zmq socket.
- *
- * \since 2.0.0 (built against 0mq version 3.1.x or later)
- *
- * \param option a valid ::socket_option
- * \param value to set the option to
- */
- void set(socket_option const option, bool const value);
-
- /*!
- * Set the value of an option in the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value to set the option to
- */
- void set(socket_option const option, uint64_t const value);
-
- /*!
- * Set the value of an option in the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value to set the option to
- */
- void set(socket_option const option, int64_t const value);
-
- /*!
- * Set the value of an option in the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param pointer to raw byte value to set the option to
- * \param length the size of the raw byte value
- */
- void set(socket_option const option, char const* value, size_t const length);
-
- /*!
- * Set the value of an option in the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param pointer to null terminated cstring value to set the option to
- */
- inline void set(socket_option const option, char const* value) { set(option, value, strlen(value)); }
-
- /*!
- * Set the value of an option in the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value to set the option to
- */
- inline void set(socket_option const option, std::string const value) { set(option, value.c_str(), value.length()); }
-
- /*!
- * Get a socket option from the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value referenced int to return value in
- */
- void get(socket_option const option, int& value) const;
-
- /*!
- * Get a socket option from the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value referenced bool to return value in
- */
- void get(socket_option const option, bool& value) const;
-
- /*!
- * Get a socket option from the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value referenced uint64_t to return value in
- */
- void get(socket_option const option, uint64_t& value) const;
-
- /*!
- * Get a socket option from the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value referenced uint64_t to return value in
- */
- void get(socket_option const option, int64_t& value) const;
-
- /*!
- * Get a socket option from the underlaying zmq socket.
- *
- * \param option a valid ::socket_option
- * \param value referenced std::string to return value in
- */
- void get(socket_option const option, std::string& value) const;
-
- /*!
- * For those that don't want to get into a referenced value this templated method
- * will return the value instead.
- *
- * \param option a valid ::socket_option
- * \return socket option value
- */
- template<typename Type>
- Type get(socket_option const option) const
- {
- Type value = Type();
- get(option, value);
- return value;
- }
-
- /*!
- * Move constructor
- *
- * Moves the internals of source to this object, there is no guarantee
- * that source will be left in a valid state.
- *
- * This constructor is noexcept and so will not throw exceptions
- *
- * \param source target socket to steal internals from
- */
- socket(socket&& source) NOEXCEPT;
-
- /*!
- * Move operator
- *
- * Moves the internals of source to this object, there is no guarantee
- * that source will be left in a valid state.
- *
- * This function is noexcept and so will not throw exceptions
- *
- * \param source target socket to steal internals from
- * \return socket reference to this
- */
- socket& operator=(socket&& source) NOEXCEPT;
-
- /*!
- * Check the socket is still valid
- *
- * This tests the internal state of the socket.
- * If creation failed for some reason or if the move functions were used
- * to move the socket internals to another instance this will return false.
- *
- * \return true if the socket is valid
- */
- operator bool() const;
-
- /*!
- * Access to the raw 0mq context
- *
- * \return void pointer to the underlying 0mq socket
- */
- operator void*() const;
-
-private:
- void* _socket;
- socket_type _type;
- zmq_msg_t _recv_buffer;
-
- // No copy
- socket(socket const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED;
- socket& operator=(socket const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED;
-
- void track_message(message_t const&, uint32_t const, bool&);
-};
-
-}
-
-#endif /* ZMQPP_SOCKET_HPP_ */
diff --git a/dep/zmqpp/zmqpp/socket_options.hpp b/dep/zmqpp/zmqpp/socket_options.hpp
deleted file mode 100644
index c5c8586cbc7..00000000000
--- a/dep/zmqpp/zmqpp/socket_options.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * \file
- *
- * \date 23 Sep 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_SOCKET_OPTIONS_HPP_
-#define ZMQPP_SOCKET_OPTIONS_HPP_
-
-namespace zmqpp
-{
-
-/** \todo Expand the information on the options to make it actually useful. */
-/*!
- * \brief possible Socket options in zmq
- */
-
-enum class socket_option {
- affinity = ZMQ_AFFINITY, /*!< I/O thread affinity */
- identity = ZMQ_IDENTITY, /*!< Socket identity */
- subscribe = ZMQ_SUBSCRIBE, /*!< Add topic subscription - set only */
- unsubscribe = ZMQ_UNSUBSCRIBE, /*!< Remove topic subscription - set only */
- rate = ZMQ_RATE, /*!< Multicast data rate */
- send_buffer_size = ZMQ_SNDBUF, /*!< Kernel transmission buffer size */
- receive_buffer_size = ZMQ_RCVBUF, /*!< Kernel receive buffer size */
- receive_more = ZMQ_RCVMORE, /*!< Can receive more parts - get only */
- file_descriptor = ZMQ_FD, /*!< Socket file descriptor - get only */
- events = ZMQ_EVENTS, /*!< Socket event flags - get only */
- type = ZMQ_TYPE, /*!< Socket type - get only */
- linger = ZMQ_LINGER, /*!< Socket linger timeout */
- backlog = ZMQ_BACKLOG, /*!< Maximum length of outstanding connections - get only */
-#if (ZMQ_VERSION_MAJOR == 2)
- // Note that this is inverse of the zmq names for version 2.x
- recovery_interval_seconds = ZMQ_RECOVERY_IVL, /*!< Multicast recovery interval in seconds */
- recovery_interval = ZMQ_RECOVERY_IVL_MSEC, /*!< Multicast recovery interval in milliseconds */
-#else
- recovery_interval = ZMQ_RECOVERY_IVL, /*!< Multicast recovery interval in milliseconds */
-#endif
- reconnect_interval = ZMQ_RECONNECT_IVL, /*!< Reconnection interval */
- reconnect_interval_max = ZMQ_RECONNECT_IVL_MAX, /*!< Maximum reconnection interval */
- receive_timeout = ZMQ_RCVTIMEO, /*!< Maximum inbound block timeout */
- send_timeout = ZMQ_SNDTIMEO, /*!< Maximum outbound block timeout */
-#if (ZMQ_VERSION_MAJOR == 2)
- high_water_mark = ZMQ_HWM, /*!< High-water mark for all messages */
- swap_size = ZMQ_SWAP, /*!< Maximum socket swap size in bytes */
- multicast_loopback = ZMQ_MCAST_LOOP, /*!< Allow multicast packet loopback */
-#else
- max_messsage_size = ZMQ_MAXMSGSIZE, /*!< Maximum inbound message size */
- send_high_water_mark = ZMQ_SNDHWM, /*!< High-water mark for outbound messages */
- receive_high_water_mark = ZMQ_RCVHWM, /*!< High-water mark for inbound messages */
- multicast_hops = ZMQ_MULTICAST_HOPS, /*!< Maximum number of multicast hops */
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1))
- ipv4_only = ZMQ_IPV4ONLY,
-#endif
-#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2))
-#if (ZMQ_VERSION_MINOR == 2)
- delay_attach_on_connect = ZMQ_DELAY_ATTACH_ON_CONNECT, /*!< Delay buffer attachment until connect complete */
-#else
- // ZMQ_DELAY_ATTACH_ON_CONNECT is renamed in ZeroMQ starting 3.3.x
- immediate = ZMQ_IMMEDIATE, /*!< Block message sending until connect complete */
-#endif
- last_endpoint = ZMQ_LAST_ENDPOINT, /*!< Last bound endpoint - get only */
- router_mandatory = ZMQ_ROUTER_MANDATORY, /*!< Require routable messages - set only */
- xpub_verbose = ZMQ_XPUB_VERBOSE, /*!< Pass on existing subscriptions - set only */
- tcp_keepalive = ZMQ_TCP_KEEPALIVE, /*!< Enable TCP keepalives */
- tcp_keepalive_idle = ZMQ_TCP_KEEPALIVE_IDLE, /*!< TCP keepalive idle count (generally retry count) */
- tcp_keepalive_count = ZMQ_TCP_KEEPALIVE_CNT, /*!< TCP keepalive retry count */
- tcp_keepalive_interval = ZMQ_TCP_KEEPALIVE_INTVL, /*!< TCP keepalive interval */
- tcp_accept_filter = ZMQ_TCP_ACCEPT_FILTER, /*!< Filter inbound connections - set only */
-#endif
-#ifdef ZMQ_EXPERIMENTAL_LABELS
- receive_label = ZMQ_RCVLABEL, /*!< Received label part - get only */
-#endif
-};
-
-}
-
-#endif /* ZMQPP_SOCKET_OPTIONS_HPP_ */
diff --git a/dep/zmqpp/zmqpp/socket_types.hpp b/dep/zmqpp/zmqpp/socket_types.hpp
deleted file mode 100644
index e59e71ca0e1..00000000000
--- a/dep/zmqpp/zmqpp/socket_types.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/**
- * \file
- *
- * \date 23 Sep 2011
- * \author Ben Gray (\@benjamg)
- */
-
-#ifndef ZMQPP_SOCKET_TYPES_HPP_
-#define ZMQPP_SOCKET_TYPES_HPP_
-
-namespace zmqpp
-{
-
-/*!
- * \brief Socket types allowed by zmq
- *
- * The socket type choose at creation must be one of these types.
- *
- * Each is designed for a different use and has different limitations.
- */
-enum class socket_type {
- /*!
- * One to one - two way connection.\n
- * Connect to ::pair.\n
- * A \c pair socket has to be connected only one other pair socket and allows
- * two way communication between them.
- */
- pair = ZMQ_PAIR,
-
- /*!
- * One to many - fan out.\n
- * Connect to ::subscribe or ::xsubscribe.\n
- * Socket is send only.\n
- * Socket will drop messages and not block.\n
- * \c publish sockets allow sending of the same message to many subscribers
- * each subscriber can limit what is sent through the socket_option::subscribe
- * settings.
- */
- publish = ZMQ_PUB,
-
- /*!
- * \note It seems doxygen can't work out which data is for the socket type and
- * which is for the socket option so both get listed for both.
- *
- * One to many - fair-queued.\n
- * Connect to ::publish or ::xpublish.\n
- * Socket is receive only.\n
- * The \c subscribe socket can connection to any number of publishers and will
- * fairly pull messages from each. The socket_option::subscribe settings can
- * be use to limit which messages are received and by default none are.
- */
- subscribe = ZMQ_SUB,
-
- /*!
- * One to many - fair-queued.\n
- * Connect to ::push.\n
- * Socket is receive only.\n
- * The \c pull socket fairly pulls messages from all pushers it is connected
- * to.
- */
- pull = ZMQ_PULL,
-
- /*!
- * One to many - load-balanced.\n
- * Connect to ::pull.\n
- * Socket is send only.\n
- * Socket will block if unable to send.\n
- * The \c push socket fairly distributes messages between any connected
- * puller sockets.
- */
- push = ZMQ_PUSH,
-
- /*!
- * One to many - fair-queued outgoing, last peer incoming.\n
- * Connect to ::reply or ::xreply.\n
- * Socket flips between send and receive only.\n
- * Socket will block if unable to send.\n
- * The \c request socket will fairly balance requests sent out to a
- * replier and then can only be used to receive until that replier
- * sends a reply.
- */
- request = ZMQ_REQ,
-
- /*!
- * One to many - load-balanced incoming, last peer outgoing.\n
- * Connect to ::request or ::xrequest.\n
- * Socket flips between send and receive only.\n
- * Socket will drop messages and not block.\n
- * The \c reply socket can only receive until it pulls a message from a
- * requester at which point it can only send until the reply is sent.
- */
- reply = ZMQ_REP,
-
- /*!
- * One to many - fan out.\n
- * Connect to ::subscribe or ::xsubscribe.\n
- * Socket is send only with the exception of special subscription messages.\n
- * Socket will drop messages and not block.\n
- * \c xpublish act the same as ::publish sockets however also allow special
- * subscription messages to be received from subscribers.
- */
- xpublish = ZMQ_XPUB,
-
- /*!
- * One to many - fair-queued.\n
- * Connect to ::publish or ::xpublish.\n
- * Socket is receive only with the exception of special subscription messages\n
- * \c xsubscribe act the same as ::subscribe sockets however also allow special
- * subscription messages to be send to connected publishers.
- */
- xsubscribe = ZMQ_XSUB,
-
- /*!
- * One to many - fair-queued incoming, load-balanced outgoing.\n
- * Connect to ::reply or ::xreply.\n
- * Socket will block if unable to send.\n
- * An \c xrequest socket balances requests between repliers and pulls replies
- * back in a fair manner. Each request is expected to have exactly one reply.
- */
- xrequest = ZMQ_XREQ,
-
- /*!
- * One to many - fair-queued incoming, targeted outgoing.\n
- * Connect to ::request or ::xrequest.\n
- * Socket will drop messages and not block.\n
- * An \c xreply socket fairly pulls in requests from requesters and will
- * label requests so it can return replies back to the correct target.
- */
- xreply = ZMQ_XREP,
-
- // To match for people who prefer the shorter versions
- pub = ZMQ_PUB, /*!< version of ::publish to match zmq name convention */
- sub = ZMQ_SUB, /*!< version of ::subscribe to match zmq name convention */
- req = ZMQ_REQ, /*!< version of ::request to match zmq name convention */
- rep = ZMQ_REP, /*!< version of ::reply to match zmq name convention */
- xpub = ZMQ_XPUB, /*!< version of ::xpublish to match zmq name convention */
- xsub = ZMQ_XSUB, /*!< version of ::xsubscribe to match zmq name convention */
- xreq = ZMQ_XREQ, /*!< version of ::xrequest to match zmq name convention */
- xrep = ZMQ_XREP, /*!< version of ::xreply to match zmq name convention */
-
- // For completion
- router = ZMQ_ROUTER, /*!< \deprecated Matches zmq 2.x xrep functionality. */
- dealer = ZMQ_DEALER /*!< \deprecated Matches zmq 2.x xreq functionality. */
-};
-
-}
-
-#endif /* ZMQPP_SOCKET_TYPES_HPP_ */
diff --git a/dep/zmqpp/zmqpp/zmqpp.cpp b/dep/zmqpp/zmqpp/zmqpp.cpp
deleted file mode 100644
index 216948e73e7..00000000000
--- a/dep/zmqpp/zmqpp/zmqpp.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Created on: 18 Aug 2011
- * Author: Ben Gray (@benjamg)
- */
-
-#include "zmqpp.hpp"
-
-namespace zmqpp
-{
-
-std::string version()
-{
- return BUILD_VERSION;
-}
-
-void version(uint8_t& major, uint8_t& minor, uint8_t& revision)
-{
- major = ZMQPP_VERSION_MAJOR;
- minor = ZMQPP_VERSION_MINOR;
- revision = ZMQPP_VERSION_REVISION;
-}
-
-void zmq_version(uint8_t& major, uint8_t& minor, uint8_t& patch)
-{
- major = ZMQ_VERSION_MAJOR;
- minor = ZMQ_VERSION_MINOR;
- patch = ZMQ_VERSION_PATCH;
-}
-
-}
diff --git a/dep/zmqpp/zmqpp/zmqpp.hpp b/dep/zmqpp/zmqpp/zmqpp.hpp
deleted file mode 100644
index 92a47ce38bf..00000000000
--- a/dep/zmqpp/zmqpp/zmqpp.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * \file
- *
- * \date 9 Aug 2011
- * \author Ben Gray (\@benjamg)
- *
- * License: http://www.opensource.org/licenses/MIT
- *
- * Copyright (C) 2011 by Ben Gray
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef ZMQPP_ZMQPP_HPP_
-#define ZMQPP_ZMQPP_HPP_
-
-/**
- * \def ZMQPP_VERSION_MAJOR
- * zmqpp major version number, generated at compile time
- */
-#define ZMQPP_VERSION_MAJOR BUILD_VERSION_MAJOR
-
-/**
- * \def ZMQPP_VERSION_MINOR
- * zmqpp minor version number, generated at compile time
- */
-#define ZMQPP_VERSION_MINOR BUILD_VERSION_MINOR
-
-/**
- * \def ZMQPP_VERSION_REVISION
- * zmqpp version revision number, generated at compile time
- */
-#define ZMQPP_VERSION_REVISION BUILD_VERSION_REVISION
-
-#include <zmq.h>
-
-#include "compatibility.hpp"
-#include "context.hpp"
-#include "exception.hpp"
-#include "message.hpp"
-#include "poller.hpp"
-#include "socket.hpp"
-
-/*!
- * \brief C++ wrapper around zmq
- *
- * All zmq++ / zmqpp functions, constants and classes live within this namespace,
- */
-namespace zmqpp
-{
-
-/*!
- * Returns the current major.minor.revision version number as a string.
- *
- * \return string version number.
- */
-std::string version();
-
-/*!
- * Retrieve the parts of the zmqpp version number.
- *
- * Set the three parameters to values representing the zmqpp version number.
- * These values are generated at library compile time.
- *
- * \param major an unsigned 8 bit reference to set to the major version.
- * \param minor an unsigned 8 bit reference to set to the minor version.
- * \param revision an unsigned 8 bit reference to set the current revision.
- */
-void version(uint8_t& major, uint8_t& minor, uint8_t& revision);
-
-/*!
- * Retrieve the parts of the 0mq version this library was built against.
- *
- * Because sections of the library are optionally compiled in or ignored
- * depending on the version of 0mq it was compiled against this method is
- * provided to allow sanity checking for usage.
- *
- * Set the three parameters to values representing the 0mq version number.
- * These values are generated at library compile time.
- *
- * \param major an unsigned 8 bit reference to set to the major version.
- * \param minor an unsigned 8 bit reference to set to the minor version.
- * \param revision an unsigned 8 bit reference to set the current revision.
- */
-void zmq_version(uint8_t& major, uint8_t& minor, uint8_t& patch);
-
-typedef context context_t; /*!< \brief context type */
-typedef std::string endpoint_t; /*!< \brief endpoint type */
-typedef message message_t; /*!< \brief message type */
-typedef poller poller_t; /*!< \brief poller type */
-typedef socket socket_t; /*!< \brief socket type */
-
-}
-
-#endif /* ZMQPP_ZMQPP_HPP_ */
diff --git a/dep/zmqpp/zmqpp_hotfix1.diff b/dep/zmqpp/zmqpp_hotfix1.diff
deleted file mode 100644
index 956902e0dfa..00000000000
--- a/dep/zmqpp/zmqpp_hotfix1.diff
+++ /dev/null
@@ -1,106 +0,0 @@
-diff --git a/dep/zmqpp/zmqpp/inet.hpp b/dep/zmqpp/zmqpp/inet.hpp
-index 5245aa4..e0c3b14 100644
---- a/dep/zmqpp/zmqpp/inet.hpp
-+++ b/dep/zmqpp/zmqpp/inet.hpp
-@@ -76,10 +76,12 @@ inline uint64_t swap_if_needed(uint64_t const value_to_check)
- * \param hostlonglong unsigned 64 bit host order integer
- * \return unsigned 64 bit network order integer
- */
-+#ifndef htonll
- inline uint64_t htonll(uint64_t const hostlonglong)
- {
- return zmqpp::swap_if_needed(hostlonglong);
- }
-+#endif
-
- /*!
- * 64 bit version of the ntohs/ntohl
-@@ -89,10 +91,12 @@ inline uint64_t htonll(uint64_t const hostlonglong)
- * \param networklonglong unsigned 64 bit network order integer
- * \return unsigned 64 bit host order integer
- */
-+#ifndef ntohll
- inline uint64_t ntohll(uint64_t const networklonglong)
- {
- return zmqpp::swap_if_needed(networklonglong);
- }
-+#endif
-
- /*!
- * floating point version of the htons/htonl
-@@ -142,7 +146,7 @@ inline double htond(double value)
-
- uint64_t temp;
- memcpy(&temp, &value, sizeof(uint64_t));
-- temp = zmqpp::htonll(temp);
-+ temp = htonll(temp);
- memcpy(&value, &temp, sizeof(uint64_t));
-
- return value;
-@@ -160,7 +164,7 @@ inline double ntohd(double value)
-
- uint64_t temp;
- memcpy(&temp, &value, sizeof(uint64_t));
-- temp = zmqpp::ntohll(temp);
-+ temp = ntohll(temp);
- memcpy(&value, &temp, sizeof(uint64_t));
-
- return value;
-diff --git a/dep/zmqpp/zmqpp/message.cpp b/dep/zmqpp/zmqpp/message.cpp
-index 5858730..4d81d24 100644
---- a/dep/zmqpp/zmqpp/message.cpp
-+++ b/dep/zmqpp/zmqpp/message.cpp
-@@ -138,7 +138,7 @@ void message::get(int64_t& integer, size_t const part) const
- assert(sizeof(int64_t) == size(part));
-
- uint64_t const* network_order = static_cast<uint64_t const*>(raw_data(part));
-- integer = static_cast<int64_t>(zmqpp::htonll(*network_order));
-+ integer = static_cast<int64_t>(htonll(*network_order));
- }
-
- void message::get(uint8_t& unsigned_integer, size_t const part) const
-@@ -170,7 +170,7 @@ void message::get(uint64_t& unsigned_integer, size_t const part) const
- assert(sizeof(uint64_t) == size(part));
-
- uint64_t const* network_order = static_cast<uint64_t const*>(raw_data(part));
-- unsigned_integer = zmqpp::ntohll(*network_order);
-+ unsigned_integer = ntohll(*network_order);
- }
-
- void message::get(float& floating_point, size_t const part) const
-@@ -228,7 +228,7 @@ message& message::operator<<(int32_t const integer)
-
- message& message::operator<<(int64_t const integer)
- {
-- uint64_t network_order = zmqpp::htonll(static_cast<uint64_t>(integer));
-+ uint64_t network_order = htonll(static_cast<uint64_t>(integer));
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint64_t));
-
- return *this;
-@@ -259,7 +259,7 @@ message& message::operator<<(uint32_t const unsigned_integer)
-
- message& message::operator<<(uint64_t const unsigned_integer)
- {
-- uint64_t network_order = zmqpp::htonll(unsigned_integer);
-+ uint64_t network_order = htonll(unsigned_integer);
- add(reinterpret_cast<void const*>(&network_order), sizeof(uint64_t));
-
- return *this;
-@@ -329,7 +329,7 @@ void message::push_front(int32_t const integer)
-
- void message::push_front(int64_t const integer)
- {
-- uint64_t network_order = zmqpp::htonll(static_cast<uint64_t>(integer));
-+ uint64_t network_order = htonll(static_cast<uint64_t>(integer));
- push_front(&network_order, sizeof(uint64_t));
- }
-
-@@ -353,7 +353,7 @@ void message::push_front(uint32_t const unsigned_integer)
-
- void message::push_front(uint64_t const unsigned_integer)
- {
-- uint64_t network_order = zmqpp::htonll(unsigned_integer);
-+ uint64_t network_order = htonll(unsigned_integer);
- push_front(&network_order, sizeof(uint64_t));
- }
-